Функция стрелки перегрузки Typescript не работает - PullRequest
0 голосов
/ 13 мая 2019

(я использую строгие нулевые проверки)

У меня есть следующая функция стрелки с перегруженным типом:

    type INumberConverter = {
      (value: number): number;
      (value: null): null;
    };
    const decimalToPercent: INumberConverter = (value: number | null): number | null => {
      if (!value) {
        return null;
      }
      return value * 100;
    };

Насколько я понимаю из других вопросов ( Могу ли яиспользовать перегрузки TypeScript при использовании синтаксиса жирных стрелок для методов класса? ) это должно быть допустимым.Тем не менее, я получаю следующую ошибку:

TS2322: Type '(value: number | null) => number | null' is not assignable to type 'INumberConverter'.   Type 'number | null' is not assignable to type 'number'.     Type 'null' is not assignable to type 'number'

Если я регулярно пишу эту функцию (с ключевым словом function):

    function decimalToPercent(value: null): null;
    function decimalToPercent(value: number): number;
    function decimalToPercent(value: number | null): number | null {
      if (!value) {
        return null;
      }
      return value * 100;
    }

Она работает без ошибок.

Мне нужно использовать функцию стрелки, чтобы this не изменилось, и мне нужна эта перегрузка, чтобы машинопись знала, decimalToPercent(1) не может быть нулем.

Почему это не работает так, как я это сделал, и как я могу это исправить?

1 Ответ

1 голос
/ 13 мая 2019

Правила совместимости между сигнатурами перегрузки и сигнатурой реализации гораздо более мягкие, чем для назначения.

В этом случае вы пытаетесь назначить функцию, которая может вернуть null функции, которая имеетперегрузка, которая запрещает возврат нуля ((value: number): number;).Компилятор по праву найдет это беспокойство.Что касается перегрузок, поскольку сигнатуры и реализация написаны как единое целое, компилятор предполагает «Вы знаете, что делаете» (правильно или нет).

Вы можете обойти это несколькими способами:

Вы можете использовать утверждение типа, хотя вы потеряете большинство проверок типов для реализации, совместимости подписи:

type INumberConverter = {
  (value: number): number;
  (value: null): null;
};
const decimalToPercent = ((value: number | null): number | null => {
  if (!value) {
    return null;
  }
  return value * 100;
}) as INumberConverter;

Вы также можете использовать обычный function и захватывать this, как в старомES5 дней, хотя это решение означает дублирование большой части сигнатуры функции:

type INumberConverter = {
  (value: number): number;
  (value: null): null;
};

class X {
    decimalToPercent: INumberConverter;
    multiper = 100;
    constructor() {
        let self = this;
        function decimalToPercent(value: number): number;
        function decimalToPercent(value: null): null;
        function decimalToPercent(value: number | null): number | null {
            if (!value) {
                return null;
            }
            // use self
            return value * self.multiper;
        };
        this.decimalToPercent = decimalToPercent;
    }
}

Или, возможно, самое простое решение - использовать bind в конструкторе и написать функцию как обычный метод:

class X {

    decimalToPercent(value: number): number;
    decimalToPercent(value: null): null;
    decimalToPercent(value: number | null): number | null {
        if (!value) {
            return null;
        }
        return value * this.multiper;
    };
    multiper = 100;
    constructor() {
        this.decimalToPercent = this.decimalToPercent.bind(this);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...