具有通用返回类型的 Typescript 函数

Law*_*Lau 6 typescript typescript-generics

type FuncGenericReturn = <T>() => T;
const funcReturnsNumber: FuncGenericReturn = (): number => 1;
Run Code Online (Sandbox Code Playgroud)

(沙盒)

收到此错误:

“数字”类型不能分配给“T”类型。'number' 可分配给类型为 'T' 的约束,但可以使用约束 '{}' 的不同子类型实例化 'T'。(2322) input.ts(1, 26):预期类型来自此签名的返回类型。

我希望打字稿能够自动将 T 推断为数字并使用它。它为什么抱怨?写这样的东西的正确方法是什么?谢谢。

jca*_*alz 18

重要的是要注意泛型类型参数的声明位置以及它们的作用域。方式

type FuncGenericReturn = <T>() => T;
Run Code Online (Sandbox Code Playgroud)

是指泛型函数具体类型。 意思是:“一个函数,它的调用者指定一个类型并返回一个类型的值。” 这基本上不可能安全地实施。想象一下,如果你有这样一个功能:<T>() => TTT

declare const funcGenericReturn: FuncGenericReturn;
Run Code Online (Sandbox Code Playgroud)

那么你应该可以这样称呼它:

const someNumber: number = funcGenericReturn<number>(); 
const someString: string = funcGenericReturn<string>();
Run Code Online (Sandbox Code Playgroud)

但是当然在运行时这些都会编译为

const someNumber = funcGenericReturn();
const someString = funcGenericReturn();
Run Code Online (Sandbox Code Playgroud)

funcGenericReturn()意味着只需要在运行时“知道”它应该首先返回 a number,然后返回a string,基于在生成 JavaScript 之前擦除的类型信息。因此,正确实施 aFuncGenericReturn将需要神奇的预知。

重申:当你有一个泛型函数时,泛型类型参数是由调用者指定,而不是由实现指定。确实,有时编译器会推断这些类型参数,以便编写代码的人不必将其拼写出来,但同样,这些推断是在调用时发生的。对同一个泛型函数的两次不同调用最终可能会对类型参数产生两种不同的选择。


让我们将其与不同但相关的类型定义进行比较:

type FuncConcreteReturn<T> = () => T;
Run Code Online (Sandbox Code Playgroud)

这里,FuncConcreteReturn是一个泛型类型,指的是一个具体的函数。更准确地说,这FuncConcreteReturn不是真正的类型;它更像是一个类型运算符,它接受一个输入类型T并产生一个输出类型() => T

对于任何特定类型T,该类型FuncConcreteReturn<T>是一个具体的函数类型,它不接受任何参数并返回一个 type 值T。所以 aFuncConcreteReturn<string>是一个不带参数并返回 a的函数string,而 aFuncConcreteReturn<number>是一个不带参数并返回 a 的函数number。请注意,这FuncConcreteReturn<string>是与 不同的类型FuncContreteReturn<number>,它们都不是 a,FuncConcreteReturn因为那不是有效类型。所以以下是有效的:

const funcReturnsNumber: FuncConcreteReturn<number> = () => 1;
const funcReturnsString: FuncConcreteReturn<string> = () => "";
Run Code Online (Sandbox Code Playgroud)

再次,funcReturnsNumber没有一个通用的功能。它是一个始终返回数字的具体函数。AndFuncConcreteReturn<T>是一个泛型类型,在T写出类型时选择的值。由于这些类型是函数类型,因此类型T由这些函数的实现者选择,而不是由调用者选择


顺便说一句,泛型函数类型之间的关系,如

type G = <T, U>(t: T, u: U) => [T, U]
Run Code Online (Sandbox Code Playgroud)

和一个泛型类型

type H<T, U> = (t: T, u: U) => [T, U]
Run Code Online (Sandbox Code Playgroud)

是后者的任何实例都将是前者的实例,但反之则不然。这意味着,如果您确实有 a FuncGenericReturn,则可以将其分配给 typeFuncConcreteReturn<string>或 a的值FuncConcreteReturn<number>

const fn: FuncConcreteReturn<number> = funcGenericReturn; // okay
const fs: FuncConcreteReturn<string> = funcGenericReturn; // okay
Run Code Online (Sandbox Code Playgroud)

或者,对于上面的GH类型,您可以这样做:

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
Run Code Online (Sandbox Code Playgroud)

好的,我希望这能让您对泛型函数和泛型类型之间的区别有所了解。祝你好运!

Playground 链接到代码


小智 2

这个语法不适合你吗?

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

Run Code Online (Sandbox Code Playgroud)