遍历联合类型数组时TypeScript编译器抛出异常错误
TypeScript循环中联合类型数组的类型收窄失效问题
先看你遇到的问题代码:
type RandomType = {x: number, y: number} type UnifiedTypes = RandomType | 0 type ArrayOfTypes = Array<(RandomType | UnifiedTypes)[]> const newIns: ArrayOfTypes = [[0, {x: 10, y: 201}], [0, {x: 10, y: 201}]] for(let i=0; i < newIns.length; ++i){ for(let j=0; j < newIns[i].length; ++j){ if(newIns[i][j] !== 0){ newIns[i][j].x = 30 // Property 'x' does not exist on type 'UnifiedTypes'. Property 'x' does not exist on type '0' } } } // 但在循环外使用字面量索引时没有问题 if(newIns[0][0] !== 0) { newIns[0][0].x = 33; // 无报错 }
问题原因
这是TypeScript类型检查器的局限性:当使用可变变量(比如i、j)作为数组索引时,编译器无法跟踪newIns[i][j]的类型在条件判断后是否依然保持收窄状态。因为变量i和j的值是动态变化的,编译器没办法确保在if(newIns[i][j] !== 0)判断之后,这个索引对应的元素没有被其他代码修改,或者索引本身有没有被重新赋值,所以它不会为这个动态索引的表达式维持收窄后的类型。
而使用**字面量索引(比如0)**时,编译器能明确知道这个固定位置的元素类型,判断后可以安全收窄类型,所以不会报错。
解决方案
有两种简单的方式解决这个问题:
1. 使用临时变量存储数组元素
把循环中当前索引的元素赋值给一个const临时变量,编译器能跟踪这个变量的类型,收窄后就可以安全访问属性:
for(let i=0; i < newIns.length; ++i){ for(let j=0; j < newIns[i].length; ++j){ const item = newIns[i][j]; if(item !== 0){ item.x = 30; // 正常编译,无报错 } } }
2. 使用数组的forEach方法遍历
forEach的回调参数会被自动推导类型,并且类型收窄能正常生效:
newIns.forEach(arr => { arr.forEach(item => { if(item !== 0){ item.x = 30; // 正常工作 } }); });
内容的提问来源于stack exchange,提问作者DigitNerd
相关产品推荐
相关产品推荐

