TypeScript无法正确识别索引类型?参数类型不兼容问题咨询
问题原因分析
先贴出你的代码:
type X = { aa: string; bb: number; }; const get = <Key extends keyof X, Value extends X[Key]>( key: Key, value: Value | ((v: Value) => Value) ) => { let newValue: Value; const x: X = { aa: '11', bb: 11 }; if (typeof value === 'function') { //Argument of type 'X[Key]' is not assignable to parameter of type 'Value'. newValue = value(x[key]); } else { newValue = value; } };
你觉得X[Key]和Value完全一致,但TypeScript不这么认为——问题出在Value extends X[Key]这个泛型约束上:Value是X[Key]的子类型,而不是等价类型。
举个实际场景:假设有人这样调用你的函数:
get('aa', (v: '11') => v)
这里Key是'aa',X[Key]是string,而Value被推导成了字面量类型'11'(它是string的子类型)。此时x[key]的类型是string,但函数参数要求的是'11',string显然不能赋值给更具体的'11',所以TypeScript就抛出了报错。
简单说,你写的泛型允许Value比X[Key]更“窄”,但x[key]的类型是更“宽”的X[Key],自然无法兼容窄类型的参数要求。
解决方案
最直接的修复方式是去掉多余的Value泛型,直接用X[Key]来定义相关类型:
type X = { aa: string; bb: number; }; const get = <Key extends keyof X>( key: Key, value: X[Key] | ((v: X[Key]) => X[Key]) ) => { let newValue: X[Key]; const x: X = { aa: '11', bb: 11 }; if (typeof value === 'function') { newValue = value(x[key]); } else { newValue = value; } };
如果一定要保留Value泛型,那需要把约束改成等价关系,而不是继承:
const get = <Key extends keyof X, Value = X[Key]>( key: Key, value: Value | ((v: Value) => Value) ) => { // ... 后续逻辑不变 };
不过这种写法意义不大,因为Value默认就是X[Key],和直接用X[Key]效果一致。
内容的提问来源于stack exchange,提问作者Guichi
相关产品推荐
相关产品推荐

