简体   繁体   English

Typescript Function 具有通用返回类型

[英]Typescript Function with Generic Return Type

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

( Sandbox ) 沙盒

Getting this error:收到此错误:

Type 'number' is not assignable to type 'T'.类型“number”不可分配给类型“T”。 'number' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{}'.(2322) input.ts(1, 26): The expected type comes from the return type of this signature. “number”可分配给类型“T”的约束,但“T”可以使用约束“{}”的不同子类型实例化。(2322) input.ts(1, 26):预期类型来自此签名的返回类型。

I would expect typescript to automatically infer T as number and just use it.我希望 typescript 自动将 T 推断为数字并使用它。 Why is it complaining?它为什么抱怨? What is the proper way to write something like this?写这样的东西的正确方法是什么? Thanks.谢谢。

It's important to pay attention to where the generic type parameters are declared and what scope they have.重要的是要注意泛型类型参数的声明位置以及它们的作用域。 The type方式

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

is a concrete type referring to a generic function .是指泛型函数具体类型 <T>() => T means: "a function whose caller specifies a type T and which returns a value of type T ." <T>() => T表示:“调用者指定类型T并返回类型T值的函数。” This is essentially impossible to implement safely.这基本上不可能安全地实施。 Imagine if you had such a function:想象一下,如果你有这样一个功能:

declare const funcGenericReturn: FuncGenericReturn;

Then you should be able to call it this way:那么你应该可以这样称呼它:

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

But of course at runtime those will both compile to但是当然在运行时这些都会编译为

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

Meaning that funcGenericReturn() would just have to "know" at runtime that it should first return a number and then a string , based on type information which is erased before the JavaScript is generated.funcGenericReturn()只需要在运行时“知道”它应该首先返回一个number ,然后返回一个string ,基于在生成 JavaScript 之前擦除的类型信息。 So properly implementing a FuncGenericReturn would require magical foreknowledge.因此正确实现FuncGenericReturn需要神奇的预知。

To reiterate: when you have a generic function, the generic type parameters are specified by the caller , not by the implementer.重申:当你有一个泛型函数时,泛型类型参数是由调用者指定,而不是由实现指定 It's true that sometimes the compiler will infer these type parameters so that the person writing the code doesn't have to spell it out, but again, these inferences are happening at call time .确实,有时编译器会推断这些类型参数,以便编写代码的人不必将其拼写出来,但同样,这些推断是在调用时发生的。 Two different calls to the same generic function could end up having two different choices for the type parameters.对同一个泛型函数的两次不同调用最终可能会对类型参数产生两种不同的选择。


Let's compare this to a different but related type definition:让我们将其与不同但相关的类型定义进行比较:

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

Here, FuncConcreteReturn is a generic type referring to a concrete function .这里, FuncConcreteReturn泛型类型,指的是具体函数 It would be more accurate to say that FuncConcreteReturn is not really a type;更准确地说, FuncConcreteReturn不是真正的类型; it's more like a type operator which takes an input type T and produces an output type () => T .它更像是一个类型运算符,它接受一个输入类型T并产生一个输出类型() => T

For any particular type T , the type FuncConcreteReturn<T> is a concrete function type which takes no parameter and returns a value of type T .对于任何特定类型T ,类型FuncConcreteReturn<T>是一个具体的函数类型,它不带参数并返回T类型的值。 So a FuncConcreteReturn<string> is a function that takes no arguments and returns a string , while a FuncConcreteReturn<number> is a function that takes no arguments and returns a number .所以一个FuncConcreteReturn<string>是一个不带参数并返回一个string的函数,而一个FuncConcreteReturn<number>是一个不带参数并返回一个number的函数。 Note that FuncConcreteReturn<string> is a different type from FuncContreteReturn<number> , and neither of them are a FuncConcreteReturn because that's not a valid type.请注意, FuncConcreteReturn<string>FuncContreteReturn<number> FuncConcreteReturn<string>是不同的类型,它们都不是FuncConcreteReturn因为它不是有效类型。 So the following is valid:所以以下是有效的:

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

Again, funcReturnsNumber is not a generic function.同样, funcReturnsNumber不是通用函数。 It is a concrete function that always returns a number.它是一个始终返回数字的具体函数。 And FuncConcreteReturn<T> is a generic type , where the value of T is chosen when the type is written out.FuncConcreteReturn<T>是一个泛型类型,其中T的值是在写出类型时选择的。 Since these types are function types, the type T is chosen by the implementer of these functions, and not by the caller .由于这些类型是函数类型,因此类型T由这些函数的实现者选择,而不是由调用者选择


By the way, the relationship between a generic function type like顺便说一句,泛型函数类型之间的关系,如

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

and a generic type like和一个泛型类型

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

is that any instance of the latter will be an instance of the former, but not vice versa.是后者的任何实例都将是前者的实例,但反之则不然。 This means that if you did have a FuncGenericReturn , you could assign it to a value of type FuncConcreteReturn<string> or a FuncConcreteReturn<number> :这意味着,如果您确实FuncGenericReturn ,则可以将其分配给FuncConcreteReturn<string>FuncConcreteReturn<number>类型的值:

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

Or, for the G and H types above, you could do this:或者,对于上面的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

Okay, I hope that gives you some understanding on the difference between generic functions and generic types.好的,我希望这能让您对泛型函数和泛型类型之间的区别有所了解。 Good luck!祝你好运!

Playground link to code Playground 链接到代码

Isn't this syntax working for you?这种语法不适合你吗?

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

I would like to make a citation from "Programming TypeScript: Making Your JavaScript Applications Scale" book by Boris Cherny, cause it helped me memorize a solid-and-simple-to-reason-about rule:我想引用 Boris Cherny 的“Programming TypeScript: Making Your JavaScript Applications Scale”一书,因为它帮助我记住了一个可靠且简单的推理规则:

Generally, Typescript will bind concrete types to your generic when you use the generic: for functions, it's when you call them , for classes, it's when you instantiate them [...], and for type aliases and interfaces, it's when you use or implement them .通常,当您使用泛型时,Typescript 会将具体类型绑定到您的泛型:对于函数,是在调用它们时,对于类,是在实例化它们时[...],对于类型别名和接口,是在您使用时或实施它们

So using a generic to define a function will not infer, but using a generic to call a function will infer.所以用泛型定义一个function不会推断,但是用泛型调用一个function会推断。

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

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