TypeScript联合接口类型加类型守卫仍报属性不存在错误
报错原因
这个报错和你的类型守卫逻辑无关,核心是TypeScript的类型收窄规则限制:
TypeScript 不会持久化记录通过数组下标反复访问的元素的类型收窄结果。因为数组元素本身是可变的,TS无法保证你两次访问TEAM.members[i]拿到的是同一个值,所以即使你在上一行已经通过isManager判断过TEAM.members[i]是Manager类型,在代码块内部再次访问TEAM.members[i]时,TS仍会将其推导为Member | Manager联合类型,自然就会提示members属性不存在。
修复方法
方法1:缓存当前遍历项为局部变量
将每次循环拿到的当前元素存为const局部变量,TS对const局部变量的类型收窄可以在整个作用域内生效,不会出现重新推导为联合类型的问题:
const setProfession = (key: string, profession: string): boolean => { for (let i = 0; i < TEAM.members.length; i++) { // 缓存当前遍历项 const current = TEAM.members[i]; if (isManager(current)) { // 此处current已被收窄为Manager类型,可正常访问members属性 for (let j = 0; j < current.members.length; j++) { const subMember = current.members[j]; if (subMember.key === key) { subMember.profession = profession; return true; } } // 补全原有逻辑遗漏:匹配管理员自身的key if (current.key === key) { current.profession = profession; return true; } } else if (current.key === key) { current.profession = profession; return true; } } return false; }
原有逻辑存在缺陷:如果传入的key对应管理员本身,代码不会为管理员设置profession属性,只会遍历其下属成员,上述代码已经补全该逻辑。
方法2:递归实现支持任意层级嵌套
如果后续业务中允许Manager下继续嵌套其他Manager,两层遍历的写法无法覆盖多层场景,可以用递归实现通用查找逻辑,同时天然规避数组下标访问的类型收窄问题:
// 先更新Manager接口定义,支持嵌套管理员 interface Manager { key: string; name: string; profession: string; members: Array<Member | Manager> } // 内部递归查找函数 const setForMemberList = (list: Array<Member | Manager>, key: string, profession: string): boolean => { for (const item of list) { // 匹配当前项 if (item.key === key) { item.profession = profession; return true; } // 如果是管理员,递归查找其下属成员 if (isManager(item) && setForMemberList(item.members, key, profession)) { return true; } } return false; } const setProfession = (key: string, profession: string): boolean => { return setForMemberList(TEAM.members, key, profession); }
内容的提问来源于stack exchange,提问作者John Wick
相关产品推荐
相关产品推荐

