TypeScript如何将联合类型的键用作索引?
解决TypeScript联合类型索引匹配报错
问题场景
需要根据输入更新对应对象的属性,输入可能对应两种不同结构的对象(Foo/Bar),尝试用联合类型的键作为索引时触发类型错误。
代码示例
interface Foo{ featureFOO1: boolean featureFOO2: boolean } interface Bar{ featureBAR1: boolean featureBAR2: boolean } interface T { foo: Foo; bar: Bar } const input = { type: 'foo', // 也可能是'bar' featureName: 'featureFOO1', // 也可能是'featureBAR1' value: false } const list = { foo: { featureFOO1: true, featureFOO2: false }, bar: { featureBAR1: true, featureBAR2: false } } type Union = Foo | Bar type KeysOfUnion<T> = T extends T ? keyof T: never type AvailableKeys = KeysOfUnion<Union> list[input.type as keyof T][input.featureName as AvailableKeys] = input.value
报错信息(翻译后)
错误:元素隐式拥有'any'类型,因为类型为'AvailableKeys'的表达式无法用于索引类型'{ featureFOO1: boolean; featureFOO2: boolean; } | { featureBAR1: boolean; featureBAR2: boolean; }'。属性'featureFOO1'不存在于类型'{ featureFOO1: boolean; featureFOO2: boolean; } | { featureBAR1: boolean; featureBAR2: boolean; }'上。(7053)
解决方案
问题根源是TypeScript无法确认input.type和input.featureName是一一对应的——比如当type为foo时,featureName可能被传入属于bar的键,所以类型检查不通过。
方案1:封装泛型函数(推荐)
通过泛型绑定type和featureName的关联关系,让TypeScript能验证两者的匹配性:
function updateFeature<K extends keyof T>( list: T, input: { type: K; featureName: keyof T[K]; value: boolean } ) { list[input.type][input.featureName] = input.value; } // 调用函数更新属性 updateFeature(list, input);
方案2:直接用类型断言(适合不封装函数的场景)
如果不想封装函数,可以通过泛型类型断言明确键的归属:
type Input<K extends keyof T> = { type: K; featureName: keyof T[K]; value: boolean }; (list[input.type as keyof T] as T[keyof T])[input.featureName as keyof T[(typeof input)['type']]] = input.value;
第一种方案不仅解决了类型错误,还让代码结构更清晰,同时保证了类型安全,避免传入不匹配的type和featureName。
内容的提问来源于stack exchange,提问作者gfteix
相关产品推荐
相关产品推荐

