使用联合索引类型无法正确索引对象的TypeScript问题
TypeScript联合类型Key索引对象时报错的原因及交叉类型解析
问题核心
当Key类型被收窄为具体值(如"A")时,赋值操作正常;但Key保留联合类型时,TypeScript抛出类型不兼容错误,且报错信息中出现了令人困惑的交叉类型。
1. 收窄类型正常的原因
在case "A"分支中,TypeScript通过类型收窄明确知道key的类型是"A",因此:
cachedData[key]的类型被推断为{A: 'A'}fetchedData[key]的类型被推断为{A: 'A', otherField: string} | undefined
此时展开cache并添加otherField后的类型,完全匹配目标属性的类型,所以赋值无报错。
2. 联合类型时报错的原因
在default分支中,key的类型仍是'A' | 'B' | 'C',TypeScript的类型检查逻辑在这里存在限制:
它无法跟踪key和cachedData[key]之间的对应关系,会错误地认为你可能给任意Key赋值任意类型的缓存数据。为了保证类型安全,它要求赋值的类型必须同时满足所有FetchedData属性类型的要求,这就导致了严格的类型校验。
3. 报错中交叉类型的来源
报错里的交叉类型{A: "A"; otherField: string;} & {B: "B"; otherField: string;} & {C: "C"; otherField: string;},来自TypeScript对fetchedData[key]的类型推断:
当索引是联合类型时,TS会将FetchedData[Key]的所有可能类型进行合并约束,错误地生成了所有属性类型的交叉类型——它认为赋值必须对所有Key都有效,而不仅仅是当前的key对应的类型。但实际上我们的赋值是和当前key严格对应的,这个推断不符合实际场景。
解决方案
方案1:类型断言
直接告诉TypeScript当前赋值的类型是匹配的:
default : { const cache = cachedData[key] fetchedData[key] = {...cache, otherField: 'otherField'} as FetchedData[Key]; }
方案2:泛型函数封装
通过泛型让TypeScript跟踪Key和对应值的类型关系:
type Key = keyof FetchedData; function updateData<K extends Key>(key: K, fetched: FetchedData, cached: CachedData) { fetched[key] = {...cached[key], otherField: 'otherField'}; } // 在default分支中调用 default : { updateData(key, fetchedData, cachedData); }
内容的提问来源于stack exchange,提问作者alveifbklsiu259
相关产品推荐
相关产品推荐

