繁体   English   中英

Typescript Function 具有通用返回类型

[英]Typescript Function with Generic Return Type

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

沙盒

收到此错误:

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

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

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

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

是指泛型函数具体类型 <T>() => T表示:“调用者指定类型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需要神奇的预知。

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


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

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

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

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

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

同样, funcReturnsNumber不是通用函数。 它是一个始终返回数字的具体函数。 FuncConcreteReturn<T>是一个泛型类型,其中T的值是在写出类型时选择的。 由于这些类型是函数类型,因此类型T由这些函数的实现者选择,而不是由调用者选择


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

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

和一个泛型类型

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

或者,对于上面的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

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

Playground 链接到代码

这种语法不适合你吗?

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

我想引用 Boris Cherny 的“Programming TypeScript: Making Your JavaScript Applications Scale”一书,因为它帮助我记住了一个可靠且简单的推理规则:

通常,当您使用泛型时,Typescript 会将具体类型绑定到您的泛型:对于函数,是在调用它们时,对于类,是在实例化它们时[...],对于类型别名和接口,是在您使用时或实施它们

所以用泛型定义一个function不会推断,但是用泛型调用一个function会推断。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM