Иметь несколько сигнатур функций в переменной типа - PullRequest
1 голос
/ 05 апреля 2019

Почему невозможно иметь несколько подписей для переменной функции "обработчик"?

Взять этот идеал, но неверный фрагмент кода в качестве примера:

class MyEntityService {

    private handleThing: (a: undefined) => undefined;
    private handleThing: <T extends object>(a: T) => T;
    private handleThing: <T extends object>(a: T | undefined) => object | T {
        if (!a) return undefined;
        // Various calls to other private methods here
        return a;
    }
}

То, что я на самом деле хочу, это что-то в этом роде: handleThing - это обработчик событий или тело then обещания, которое должно иметь лексическое связывание this (функция стрелки - самый простой способ добиться этого). Предполагается, что handleThing поддерживает несколько подписей, так что наиболее подходящая из них может быть выбрана контекстом (т.е. в зависимости от того, где она используется).

Я также попробовал следующее, но переменная-обработчик в итоге имела тип any, т. Е. Вся типизация была фактически пропущена:

class MyEntityService {

    private handleThing = this.handleThing_.bind(this);
    private handleThing_(a: undefined): undefined;
    private handleThing_<T extends object>(a: T): T;
    private handleThing_<T extends object>(a: T | undefined): T | undefined {
        if (!a) return undefined;
        // Various calls to other private methods here
        return a;            
    }
}

Наличие только handleThing: <T extends object>(a: T | undefined) => object | undefined не идеально:

  1. Он не отображается в сигнатуре действительной функции так, как мне нужно, то есть, когда мой ввод не похож на нуль, мой тип возвращаемого значения, безусловно, также не нулевой; и
  2. Некоторые другие методы, которые я определил в классе, ожидают, чтобы давать и получать ненулевые объекты, поэтому функция обработчика, как указано выше, не может использоваться для каждого обещания или обработчика события.

Можно было бы использовать async функции и покончить с переменными функций-обработчиков, но это противоречило бы установленным соглашениям о коде, которые моя команда создала для проекта, в котором у меня была эта дилемма.

Поэтому я спрашиваю:

  1. Есть ли лучший способ достичь моей цели - сохранить безопасность типов в переменных функций обработчика в TypeScript?
  2. Кто-нибудь знает, почему не работает первый фрагмент?
  3. Есть ли вероятность того, что первый фрагмент может когда-нибудь сработать (т. Е. Выбор сигнатуры объединенной функции в дорожной карте)?

1 Ответ

1 голос
/ 05 апреля 2019

Чтобы ваш первый фрагмент работал, вы должны рассматривать handleThing как инициализированное свойство, а не как метод;это означает, что вы даете ему аннотацию одного типа и одно значение.Обратите внимание, что тип перегруженной функции может быть представлен либо как пересечение каждой сигнатуры (например, ((x: string)=>number) & ((x: number)=>string)), либо как отдельный тип объекта с несколькими голыми сигнатурами функций (например, { (x: string): number; (x: number): string; }).Например:

class MyEntityService {
  private handleThing: {
    (a: undefined): undefined;
    <T extends object>(a: T): T;
  } = <T extends object>(a: T | undefined) => {
    if (!a) return undefined;
    // Various calls to other private methods here
    return a;
  }
}

Второй фрагмент будет работать так, как вы ожидаете, после обновления до TypeScript 3.4 или выше, поскольку в TypeScript 3.4 добавлена ​​улучшенная поддержка , выводящая универсальные типы из использования универсальных функций ,В TypeScript 3.3 или ниже, возвращаемое значение bind() будет обрезать все шаблоны и заменить их на any, как вы видели.

Наконец, я не уверен, почему вы не идете наодна подпись:

class MyEntityService {
  private handleThing = <T extends object | undefined>(a: T): T => {
    if (!a) return undefined as T; // have to assert here
    // Various calls to other private methods here
    return a;
  }
}

, поскольку (x: undefined) => undefined должна совпадать с этой подписью, если вы разрешите T диапазон как object, так и undefined.

В любом случае, надеюсь, это поможет;удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...