TypeScript联合类型类型守卫为何在变量索引访问时报错?
为什么TypeScript中变量索引无法触发类型守卫的收窄?
核心原因
TypeScript的类型守卫能生效,依赖于它能确定被检查的值和后续操作的是同一个引用:
- 用常量索引(比如
o.q[0])时,TS明确知道你操作的是数组中固定位置的元素,类型守卫isMulti检查后,会直接把这个位置的类型收窄为IMulti,后续访问ans自然没问题。 - 用变量
z索引时,TS无法保证:- 从执行
isMulti(o.q[z])到赋值o.q[z].ans的过程中,z的值没有被修改(比如其他代码把z改成了0,而o.q[0]是ISingle类型); - 数组中
z对应的元素没有被替换成其他类型(比如在判断后,有代码把o.q[z]改成了ISingle实例)。
出于安全性考虑,TS不会对变量索引的数组元素做类型收窄。
- 从执行
循环迭代时的问题也是同一个逻辑:循环变量(比如i)是动态变化的,TS无法跟踪每一次循环中o.q[i]的类型是否和类型守卫检查时一致,所以同样会报错。
解决方案
解决思路是把数组元素先存入临时变量,让TS明确后续操作的是同一个引用,类型守卫就能正常生效:
1. 变量索引场景
var z = 1; const item = o.q[z]; // 先存临时变量 if (isMulti(item)) { item.ans = []; // 类型守卫生效,无报错 }
2. 循环迭代场景
用for...of直接遍历元素(推荐):
for (const item of o.q) { if (isMulti(item)) { item.ans = []; } }
或者用forEach:
o.q.forEach(item => { if (isMulti(item)) { item.ans = []; } });
如果必须用索引循环,同样先存临时变量:
for (let i = 0; i < o.q.length; i++) { const item = o.q[i]; if (isMulti(item)) { item.ans = []; } }
内容的提问来源于stack exchange,提问作者Andrew M
相关产品推荐
相关产品推荐

