具有泛型的Typescript箭头函数的语法是什么?


Answers:


231

完整的示例解释了Robin所引用的语法...为我带回家了:

通用功能

如下所示的效果很好:

function foo<T>(x: T): T { return x; }

但是,使用箭头通用函数不会:

const foo = <T>(x: T) => x; // ERROR : unclosed `T` tag

解决方法:对通用参数使用扩展,以提示编译器是通用的,例如:

const foo = <T extends unknown>(x: T) => x;

1
是否有可能为声明一些预定义的泛型类型const foo?即type GenericFun<T, A=T> = (payload: A) => T;然后使const foo: GenericFun仍然通用而不提供T类型?
ciekawy

@ ciekawy,AFAIK,不是,我认为这是有道理的。泛型在某种意义上是关于允许更高阶的类型。GenericFun<T, A=T>定义一个包括其他类型 GenericFun<number>和的集合GenericFun<string>。允许通用类型直接构成类型注释(例如const)const foo: GenericFun,但是会趋于侵蚀静态安全性,否则会通过要求特殊性来提供安全性,例如,const foo: GenericFun<string>const foo: GenericFun<number>
jbmilgrom

7
您的第二个示例只是.tsx文件(TypeScript + JSX)中的错误。在.ts文件中,它可以正常工作,如您在TypeScript操场上所见。
danvk

46
较新的Typescript编译器还支持尾部逗号const foo = <T,>(x: T) => x;来避免JSX的歧义。
汤玛斯

1
@danvk值得一提的是,这仅适用于禁止TS文件中包含JSX的用户-如果将项目配置为允许TS文件中包含JSX,则您仍然需要“扩展名”或结尾的逗号
Matt

65

我发现上面的例子令人困惑。我正在使用React和JSX,所以我认为这使情况变得复杂。

我从TypeScript Deep Dive中得到了澄清,其中指出了箭头泛型:

解决办法:对通用参数使用扩展,以提示编译器是通用的,这来自于一个简单的示例,该示例对我有所帮助。

    const identity = < T extends {} >(arg: T): T => { return arg; }

8
然后“ T扩展任何”将支持void。
穆罕默德·法赫瑞丁

47

如果您在.tsx文件中,则不能只写<T>,但这可以工作:

const foo = <T, >(x: T) => x;

extends {}hack 相对,此hack至少保留了意图。


他们是否打算解决此问题?
亚历山大·金

我想没有太多,可能这个做...的JSX和打字稿通用语法只是冲突在这里..
MB21

1
太棒了-到目前为止,这是最好的答案:完美运行且完全不会改变行为!
Geoff Davids

默认类型参数类型呢?const foo = <T = any,>(x: T) => x不起作用……
Mikhail Vasin

34

语言规范在p.64f中说

形式为<T>(...)=> {...}的构造可以解析为具有类型参数的箭头函数表达式,或应用于没有类型参数的箭头函数的类型断言。它被解析为前者[..]

例:

// helper function needed because Backbone-couchdb's sync does not return a jqxhr
let fetched = <
           R extends Backbone.Collection<any> >(c:R) => {
               return new Promise(function (fulfill, reject) {
                   c.fetch({reset: true, success: fulfill, error: reject})
               });
           };


3

尽管流行的答案是extends {}可行的并且比更好extends any,但它迫使T成为对象。

const foo = <T extends {}>(x: T) => x;

为了避免这种情况并保留类型安全性,您可以extends unknown改用

const foo = <T extends unknown>(x: T) => x;

1

我使用这种类型的声明:

const identity: { <T>(arg: T): T } = (arg) => arg;

它允许您在需要时为函数定义其他道具,在某些情况下,它可以使函数主体与通用定义保持更清洁。

如果您不需要其他道具(诸如名称空间之类的东西),则可以简化为:

const identity: <T>(arg: T) => T = (arg) => arg;

1

这么晚了,但是有了ES6,不需要扩展它仍然对我有用.... :)

let getArray = <T>(items: T[]): T[] => {
    return new Array<T>().concat(items)
}

let myNumArr = getArray<number>([100, 200, 300]);
let myStrArr = getArray<string>(["Hello", "World"]);
myNumArr.push(1)
console.log(myNumArr)

这对我不起作用,我必须像这样添加一个逗号:<T, >。如@Thomas评论(@jbmilgrom)答案中所述
阿波罗

发布解决方案之前,您应该阅读其他解决方案。您的解决方案已发布并附有说明。它仅在.ts文件中起作用,而不在.tsx文件中起作用。
艾萨克·帕克
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.