Как аннотировать функцию, которая принимает класс и возвращает фабрику со статическими членами? - PullRequest
0 голосов
/ 08 мая 2018

Аналогично этот вопрос , но я хочу, чтобы статические члены класса также были доступны.

Вот что я пытаюсь:

function noNew<T>(clazz: new () => T): { (): T }
function noNew<T, T1>(clazz: new (arg1: T1) => T): { (arg1: T1): T }
function noNew<T>(clazz: new (...a: any[]) => T): { (...b: any[]): T } {
    const factory = (...args: any[]) => {
        return new clazz(...args);
    };

    // I want the return type annotation to be aware of this step
    Object.assign(factory, clazz);

    return factory;
}

class Test {
    static one() {}
    two: 'two';
}

const test = noNew(Test);
test.one(); // <- unresolved function or method 'one'

Как видите, машинопись не знает, что я добавил статические члены к возвращаемому значению. Как мне представить это как аннотацию?

Бонусные баллы, если вы можете исключить test.prototype.

1 Ответ

0 голосов
/ 09 мая 2018

Как насчет этого:

// 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

Хорошо выглядит. Надеюсь, это поможет!

...