通过方括号访问对象时联合类型的TypeScript类型推断问题
TypeScript联合类型动态访问的类型窄化问题解决方法
问题原因
TypeScript的控制流分析无法跟踪多次动态属性访问的关联关系。每次调用dummy.list[dummy.currentObjectId]时,TypeScript都会将其视为独立的联合类型访问操作,即便你已经通过type字段做了判断,后续再次访问该动态属性时,类型仍会回到联合类型。而先将结果赋值给变量后,TypeScript能跟踪变量的类型变化,从而正确完成类型窄化。
解决方案
1. 先将动态访问结果赋值给变量(最推荐)
这是最简单且安全的方式,把动态索引的结果存入变量后,TypeScript就能在控制流中正确窄化类型:
const currentObj = dummy.list[dummy.currentObjectId]; if (currentObj.type === types.BAR) { // 此处currentObj的类型被正确推断为TObject_BAR const assign = currentObj.type; // 类型为types.BAR }
2. 优化类型定义,建立索引与类型的关联
如果希望TypeScript在编译期就识别currentObjectId与list键的对应关系,可以通过泛型约束强化类型定义:
// 让currentObjectId必须是list的键之一 type Example<T extends TPossibleObjectType> = { id: string; currentObjectId: keyof typeof T['list']; list: Record<keyof typeof T['list'], T>; }; // 或者更精确地绑定对象id与类型的关系 type ExampleWithTypedIds<T extends TPossibleObjectType> = { id: string; currentObjectId: T['id']; list: Record<T['id'], T>; }; // 使用satisfies让TypeScript自动推断类型 const dummy = { id: 'ex', currentObjectId: 'object_foo', list: { object_foo: { id: 'object_foo', type: types.FOO }, object_bar: { id: 'object_bar', type: types.BAR }, }, } satisfies ExampleWithTypedIds<TObject_FOO | TObject_BAR>;
注意:如果currentObjectId是运行时动态生成的值,这种方式仍需要配合变量赋值来做类型窄化。
3. 类型断言(仅在确定类型时使用)
如果能绝对保证当前currentObjectId对应的对象类型,可以使用类型断言,但这种方式会跳过TypeScript的类型检查,存在运行时风险:
const targetObj = dummy.list[dummy.currentObjectId] as TObject_BAR; if (targetObj.type === types.BAR) { const assign = targetObj.type; // 类型为types.BAR }
内容的提问来源于stack exchange,提问作者yusuf
相关产品推荐
相关产品推荐

