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

Я даже не уверен, возможно ли то, что я хочу сделать.Я использую фреймворк, который предоставляет декораторы для внедрения зависимостей, и очень сложно правильно напечатать приведенный ниже пример кода:

class Control {
  constructor(
    options: {
      tabIndex?: number
    },
    callbacks: {
      onChange?: (event: any) => void,
    }
  ) {
  
  }
}

@inject(Factory.of(Control))
class Form {
  public GetControl: any;
  public control: Control;
  
  constructor(GetControl: any) {
    this.GetControl = GetControl;
  }
  build() {
    this.control = this.GetControl({tabIndex: 0}, null);
  }
}

Есть ли способ, которым я могу установить тип GetControl без необходимости дублировать определения параметров в классе управления следующим образом:

public GetControl: (
    options: {
      tabIndex?: number
    },
    callbacks: {
      onChange?: (event: any) => void,
    }
  ) => Control;

1 Ответ

0 голосов
/ 13 декабря 2018

Начиная с TypeScript 2.8, мы можем получить тип GetControl из класса, используя кортежи в параметрах отдыха (читай здесь ) и условные типы ( документы ).

class Control {
  constructor(
    options: {
      tabIndex?: number
    },
    callbacks: {
      onChange?: (event: any) => void,
    }
  ) {

  }
}

// Create a function with the same return type and parameters as a constructor
type Factory<T extends new (...a: any[]) => any> =
  T extends new (...a: infer A) => infer R ? (...a: A) => R : never;

class Form {
  ;
  public control: Control;
  // Shorthand field definition, same as your code but shorter :)
  constructor(public GetControl: Factory<typeof Control>) {
  }
  build() {
    this.control = this.GetControl({ tabIndex: 0 }, null);
  }
}

Тип Factory преобразует конструктор в функцию с теми же аргументами.Для этого мы используем поведение вывода условных типов.Если T расширяет тип конструктора (что он делает из-за ограничения типа), мы просим компилятор вставить в A кортеж, содержащий типы всех параметров (...a: infer A) и в R возвращаемый типконструктор (=> infer R, это будет тип экземпляра класса).

Используя A и R, мы можем определить требуемую функцию с типом возвращаемого значения R, и мы распространяем аргументы конструктора на аргументы функции ((...a: A) => R)

...