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

时间:2020-02-11 22:30:20

标签: typescript typescript-generics

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

Sandbox

出现此错误:

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

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

2 个答案:

答案 0 :(得分:6)

请务必注意泛型类型参数的声明位置以及它们的作用域。类型

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()只需在运行时“知道”它应该首先基于类型信息erased返回一个number,然后返回一个string。在生成JavaScript之前。因此,正确实施FuncGenericReturn将需要神奇的知识。

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


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

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

在这里,FuncConcreteReturn泛型,是指具体函数。说FuncConcreteReturn实际上不是一种类型会更准确。它更像 type运算符,它接受输入类型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不是通用函数。这是一个始终返回数字的具体函数。 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 link to code

答案 1 :(得分:1)

这种语法对您不起作用吗?

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