Функция Typescript с Generi c Возвращаемый тип - PullRequest
1 голос
/ 12 февраля 2020
type FuncGenericReturn = <T>() => T;
const funcReturnsNumber: FuncGenericReturn = (): number => 1;

( Песочница )

Получение этой ошибки:

Тип 'номер' не может быть назначен типу 'T'. 'Number' присваивается ограничению типа 'T', но можно создать экземпляр T с другим подтипом ограничения '{}'. (2322) input.ts (1, 26): ожидаемый тип происходит из тип возвращаемой подписи.

Я ожидаю, что машинопись автоматически выведет T как число и просто использует его. Почему это жалуется? Как правильно написать что-то подобное? Спасибо.

Ответы [ 2 ]

4 голосов
/ 12 февраля 2020

Важно обратить внимание на то, где объявлены параметры типа c и в какой области они находятся. Тип

type FuncGenericReturn = <T>() => T;

представляет собой конкретный тип , относящийся к функции generi c . <T>() => T означает: «функция, для которой caller указывает тип T и которая возвращает значение типа T». Это практически невозможно реализовать безопасно. Представьте себе, если бы у вас была такая функция:

declare const funcGenericReturn: FuncGenericReturn;

Тогда вы сможете назвать ее так:

const someNumber: number = funcGenericReturn<number>(); 
const someString: string = funcGenericReturn<string>();

Но, конечно, во время выполнения они оба скомпилируются в

const someNumber = funcGenericReturn();
const someString = funcGenericReturn();

Это означает, что funcGenericReturn() просто должен "знать" во время выполнения, что он должен сначала вернуть number, а затем string, основываясь на информации о типе, которая стерта перед тем JavaScript генерируется. Поэтому правильная реализация FuncGenericReturn потребует магического предузнания.

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


Давайте сравним это с другим, но связанным определением типа:

type FuncConcreteReturn<T> = () => T;

Здесь FuncConcreteReturn - это generi c тип , относящийся к конкретной функции . Точнее было бы сказать, что FuncConcreteReturn на самом деле не тип; это больше похоже на оператор типа , который принимает тип ввода T и производит тип вывода () => T.

Для любого конкретного типа T тип FuncConcreteReturn<T> является функциональным типом concrete , который не принимает параметров и возвращает значение типа T. Таким образом, FuncConcreteReturn<string> - это функция, которая не принимает аргументов и возвращает string, а FuncConcreteReturn<number> - это функция, которая не принимает аргументов и возвращает number. Обратите внимание, что FuncConcreteReturn<string> отличается от FuncContreteReturn<number>, и ни один из них не является FuncConcreteReturn, потому что это недопустимый тип. Таким образом, действует следующее:

const funcReturnsNumber: FuncConcreteReturn<number> = () => 1;
const funcReturnsString: FuncConcreteReturn<string> = () => "";

Опять же, funcReturnsNumber - это , а не универсальная c функция. Это конкретная функция, которая всегда возвращает число. И FuncConcreteReturn<T> - это generi c type , где значение T выбирается при записи типа. Так как эти типы являются типами функций, тип T выбирается реализатором этих функций, а не вызывающей стороной .


. Кстати, связь между типом функции generi c, таким как

type G = <T, U>(t: T, u: U) => [T, U]

, и типом generi c, таким как

type H<T, U> = (t: T, u: U) => [T, U]

, заключается в том, что любой экземпляр последнего будет экземпляром из первых, но не наоборот. Это означает, что если у вас действительно есть FuncGenericReturn, вы можете присвоить ему значение типа FuncConcreteReturn<string> или FuncConcreteReturn<number>:

const fn: FuncConcreteReturn<number> = funcGenericReturn; // okay
const fs: FuncConcreteReturn<string> = funcGenericReturn; // okay

или для * Типы 1098 * и H выше, вы можете сделать это:

const g: G = <T, U>(t: T, u: U) => [t, u];
g("a", 1); // okay
g(1, "a"); // okay

const h1: H<string, number> = g; // okay
h1("a", 1); // okay
h1(1, "a"); // error

const h2: H<number, string> = g; // okay
h2(1, "a"); // okay
h2("a", 1); // error

Хорошо, я надеюсь, что это даст вам некоторое представление о разнице между функциями generi c и типами generi c , Удачи!

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

1 голос
/ 12 февраля 2020

Разве этот синтаксис не работает для вас?

type FuncGenericReturn<T> = () => T;
const funcReturnsNumber: FuncGenericReturn<number> = () => 1;

...