Как насчет этого:
// works for some constructor types
type ConstructorToFunction<C extends new (...args: any[]) => any> = (
C extends (new () => infer T) ? () => T :
C extends (new (a: infer A) => infer T) ? (a: A) => T :
C extends (new (a: infer A, b: infer B) => infer T) ? (a: A, b: B) => T :
C extends (new (...args: any[]) => infer T) ? (...args: any[]) => T :
C // bail out
) & { [K in Exclude<keyof C, 'prototype'>]: C[K] }
Здесь я использую условные типы , представленные в TypeScript 2.8, чтобы попытаться представить преобразование конструктора в функцию с теми же аргументами. Большая условная часть заменяет ваш набор перегрузок, а пересечение с {[K in Exclude...
выполняет копирование статических частей.
Вот как бы я набрал функцию noNew()
:
function noNew<C extends new (...args: any[]) => any>(
clazz: C
): ConstructorToFunction<C>;
function noNew(
clazz: new (...args: any[]) => any
): { (...args: any[]): any } {
const factory = (...args: any[]) => {
return new clazz(...args);
};
Object.assign(factory, clazz);
return factory;
}
Одиночная перегрузка все еще полезна, потому что функции, возвращающие условные типы, трудно реализовать без большого количества утверждений типа, поэтому перегрузка освобождает меня от этого.
Посмотрим, работает ли он:
class Test {
static one() { }
two: 'two' = 'two';
}
const test = noNew(Test);
test.one(); // works
Хорошо выглядит. Надеюсь, это поможет!