Как определить перегруженные подписи для const в машинописи? - PullRequest
0 голосов
/ 22 апреля 2020

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

function hello(name: number): void;
function hello(name: string): void;
function hello(name: number | string): void {
  // ...
}

Я пытался определить эту функцию как const, например:

const hello = (name: number | string): void => {
  // ...
}

Но не уверен, как объявить подписи перегрузки на нем:

(name: number): void; 
(name: string): void;

Пожалуйста, помогите, спасибо

Ответы [ 2 ]

1 голос
/ 22 апреля 2020

Учитывая, что ваша перегруженная инструкция функции hello, вы можете обнаружить тип, который компилятор для него сам выводит, записав псевдоним типа в его тип и проверяя его с помощью IntelliSense при наведении поверх него в вашей IDE:

type Hello = typeof hello;
/* type Hello = {
    (name: number): void;
    (name: string): void;
} */

Здесь вы можете видеть, что Hello считается типом объекта с двумя сигнатурами вызовов , представляющими сигнатуры вызовов, которые вы объявили в своей перегрузке список в том же порядке.

Вы также можете написать эквивалентный тип как пересечение типов функций:

type AlsoHello = ((name: string) => void) & ((name: number) => void);

Если у вас есть типы функций F1 и F2, затем F1 & F2 представляет перегруженную функцию, где подпись F1 проверяется перед подписью F2. В (все более и более устаревшем) TypeScript spe c говорится:

Хотя обычно верно, что A & B эквивалентен B & A, порядок составляющих типы могут иметь значение при определении вызова и создания сигнатур типа пересечения.

В остальной части ответа я буду использовать версию object-type-with-множественные call-подписи вместо версия пересечения стрелки-функции-подписи.


В любом случае, в этом конкретном случае, когда обе подписи возвращают void, вы можете переписать hello как const без ошибок, если вы аннотируете его указанным выше типом:

const helloConst: {
  (name: number): void;
  (name: string): void;
} = (name: number | string): void => {
  // ...
}

В общем, предостережение, хотя ... перегруженные операторы не проверяются так строго, как const назначение. Перегруженные операторы функций позволяют типу возврата сигнатуры реализации соответствовать объединению типов возврата сигнатур вызовов, даже если это небезопасно:

function goodbye(name: number): number;
function goodbye(name: string): string;
function goodbye(name: number | string): number | string {
  return typeof name === "number" ? name + 1 : name + "!";
}

В приведенном выше нет ошибки компилятора. Реализация goodbye() возвращает number | string, и вы можете изменить typeof name === "number" на typeof name !== "number", и компилятор все равно не предупредит вас. Обычно это считается функцией, а не ошибкой.

Но теперь, если вы написали это как const, вы получите ошибку:

const goodbyeConst: { // error!
  (name: number): number;
  (name: string): string;
} = (name: number | string): number | string =>
    typeof name === "number" ? name + 1 : name + "!";
// Type '(name: string | number) => string | number' 
// is not assignable to 
// type '{ (name: number): number; (name: string): string; }'.

Назначение const проверено более строго, и компилятор (правильно) жалуется, что вы не можете безопасно обрабатывать функцию типа (name: string | number) => string | number как функцию типа ((name: string) => string) & ((name: number) => number). В конце концов, реализация всегда может вернуть string, который соответствует сигнатуре реализации, но не соответствует сигнатуре вызова number.

В любом случае, в таком случае можно использовать тип утверждение вместо аннотации:

const goodbyeConstAssert = ((name: number | string): number | string =>
  typeof name === "number" ? name + 1 : name + "!") as { // error!
    (name: number): number;
    (name: string): string;
  }

Это компилируется без ошибок.


Хорошо, надеюсь, это поможет; удачи!

Детская площадка ссылка на код

1 голос
/ 22 апреля 2020

Вы можете определить тип / интерфейс с помощью вызываемых подписей и использовать его для ввода переменной:

type Hello = {
    (name: number): void,
    (name: string): void,
}

const hello: Hello = (name: number | string): void => {
    // ...
}

hello(1); // ok
hello('1'); // ok

declare const wrong: string | number;
// @ts-expect-error
hello(wrong)

Детская площадка

...