TypeScript无法推断外部泛型参数T的keyof T类型问题
TypeScript泛型函数类型推断异常问题
以下代码片段复现了问题:
type Bar = { prop: string, numProp: number } type Other = { prop: number, strProp: string } type Foo<T> = { func: <P extends keyof T>(propName: P, propValue: T[P]) => T; } const init = <T>(): Foo<T> => { return {func: <P extends keyof T>(propName: P, propValue: T[P]): T => { return {} as T }}; } let foobar: Foo<Bar> = init<Bar>(); // 预期合法但报错: const res1 = foobar.func('prop', 'hello'); // 错误:参数类型"prop"无法赋值给keyof T类型 // 错误:参数类型"hello"无法赋值给Bar[keyof T]类型 const res2: Bar = foobar.func('prop', 'hello'); // 合法 const res3 = foobar.func<keyof Bar>('prop', 'hello'); // 合法 const res4: Other = foobar.func('prop', 'hello'); // 错误:初始化类型Bar无法赋值给变量类型Other const res5 = foobar.func<keyof Other>('prop', 'hello'); // 合法:不符合预期逻辑 const res6 = foobar.func<keyof Other>('prop', 5); // 错误:参数类型5无法赋值给Bar[keyof Bar]类型 const res7 = foobar.func<keyof Other>('strProp', 'hello'); // 错误:参数类型"strProp"无法赋值给keyof Bar类型 const res8: Bar = foobar.func('prop', 5); // 错误:参数类型5无法赋值给Bar["prop"]类型 const res9 = foobar.func<keyof Bar>('prop', 5); // 合法
问题分析
调用init<Bar>()初始化foobar后,TypeScript无法在func内部正确将泛型T识别为Bar,导致keyof T没有展开为keyof Bar。
- 显式指定返回值类型为
Bar时,keyof T会被正确识别为keyof Bar,代码合法;从第二个参数的错误信息能看出,TypeScript其实已经知道T是Bar,问题仅出在<P extends keyof T>的类型推断上。 - 显式指定
P为keyof Bar时代码合法,但存在逻辑矛盾:res4中把返回值设为Other会报错(正确识别返回类型为Bar),但res5指定P为keyof Other却被允许;而res6和res7又会因实际遵循Bar的键规则报错,说明传入的keyof Other被忽略。 res8被正确识别为非法,但res9却被允许——尽管Bar['prop']是string而非number,说明TypeScript对keyof Bar的类型约束也未完全生效。
预期行为
希望T在func中被明确识别为Bar,P被约束为extends keyof Bar,仅允许prop和numProp作为propName的有效值;调用func('prop')时,第二个参数类型自动匹配Bar['prop']对应的string类型,即以下代码应合法:
let foobar: Foo<Bar> = init<Bar>(); const res1 = foobar.func('prop', 'hello');
内容的提问来源于stack exchange,提问作者iainmackay85
相关产品推荐
相关产品推荐

