为何TypeScript无法推断使用keyof的泛型函数参数类型?
keyof泛型函数的参数类型? 这个问题的核心在于TypeScript对泛型函数作为参数传递时的类型推断逻辑,咱们一步步拆解:
核心原因:泛型函数 vs 具体类型函数
当你把一个泛型函数(比如带<K extends keyof MyType>的myFunction)传给另一个泛型函数cantInfer时,TypeScript不会自动为这个泛型函数实例化出一个具体的类型版本。它会把myFunction的类型保留为泛型函数类型(即<K extends keyof MyType>(key: K) => string),而不是一个绑定了具体K值的函数实例。
而cantInfer的定义要求第一个参数fn的参数类型In必须和第二个参数i的类型完全匹配。这时候TypeScript无法找到一个既能满足fn的泛型约束(K extends keyof MyType),又能精准匹配i的具体类型'a'的In类型,所以推断失败并报错。
两段代码的差异分析
报错代码解析
type MyType = { a: string, b: string } function cantInfer<In, Out>(fn: (i: In) => Out, i: In) { } function myFunction<K extends keyof MyType>(key: K): string { return ''; } cantInfer(myFunction, 'a'); // 类型推断失败
这里myFunction是一个泛型函数,它的参数类型是受约束的泛型类型K,而不是一个具体的类型。当它被传给cantInfer时,TypeScript会把fn的类型识别为<K extends keyof MyType>(key: K) => string——这是一个“泛型函数类型”,而非某个具体的函数。此时cantInfer需要In同时满足:
- 是
fn的参数类型(即K extends keyof MyType) - 等于第二个参数的类型
'a'
由于TypeScript不会自动将K绑定到'a'来实例化myFunction,这两个条件无法同时满足,因此报错。
正常代码解析
type MyType = { a: string, b: string } function cantInfer<In, Out>(fn: (i: In) => Out, i: In) { } function myFunction(key: keyof MyType): string { return ''; } cantInfer(myFunction, 'a'); // 类型推断成功
这里myFunction的参数类型是具体的联合类型keyof MyType(即'a' | 'b'),不是泛型。当传给cantInfer时,TypeScript可以轻松推断出:
In为'a'(因为第二个参数是'a',且'a'属于keyof MyType的子集,符合fn的参数类型要求)Out为string
所有类型都能匹配,因此没有问题。
解决方法
如果想要保留myFunction的泛型特性,同时让cantInfer正确推断类型,可以手动指定泛型参数,或者先实例化泛型函数:
- 手动指定
cantInfer的泛型
cantInfer<'a', string>(myFunction, 'a');
- 先实例化
myFunction为具体函数
const myFunctionForA = myFunction<'a'>; cantInfer(myFunctionForA, 'a');
内容的提问来源于stack exchange,提问作者Anthony Naddeo

