为何使用对象键取值时TypeScript类型守卫失效?(TS2345)
为什么TypeScript中直接用
obj2?.[key]时类型守卫失效,赋值给变量后就正常? 这本质是TypeScript的类型推断机制对动态属性的多次独立访问无法做关联跟踪导致的。
具体原因:
- 当你直接写
obj2?.[key]时,每次调用这个表达式,TypeScript都会重新计算它的类型——因为obj2是Obj类型(值为string | Obj),key是动态字符串,TypeScript无法保证两次obj2?.[key]访问的是同一个值,更没法保证两次访问的类型一致。 - 你写
typeof obj2?.[key] !== 'string'时,TypeScript只能推断这一次访问的结果不是字符串,但下一次写obj2?.[key]传参时,它还是会认为这个值可能是string | Obj,所以抛出类型不匹配的错误。
解决方法:把动态属性的值存到变量里
把obj2?.[key]赋值给一个变量后,TypeScript会对这个变量做类型窄化——当你用typeof判断变量类型后,后续使用这个变量时,TypeScript会记住它的类型已经被守卫成Obj了,不会再当成联合类型处理。
修改后的代码示例:
type Obj = { [val: string]: string | Obj }; const countKeys = (obj1: Obj, obj2: Obj): number => { const count = Object.entries(obj1).reduce((prev, [key, value]) => { if (typeof value === 'object') { // 先把值存到变量里 const nestedObj2 = obj2?.[key]; // 更严谨的类型判断,无需非空断言 if (typeof nestedObj2 === 'object' && nestedObj2 !== null) { return prev + countKeys(value, nestedObj2); } else { return prev + 1; } } return obj2?.[key] ? prev : prev + 1; }, 0); return count; }; const test1 = { a: '1', b: '2', c: '3', d: { e: '41', f: '42', }, g: { h: '1', }, } const test2 = { a: '1', b: '2', d: { e: '41', } } console.log(countKeys(test1, test2));
补充说明:
上面的写法里,我们通过typeof nestedObj2 === 'object' && nestedObj2 !== null的判断,完全排除了string和undefined的可能,让TypeScript明确知道nestedObj2是Obj类型,不需要额外的非空断言,类型完全安全。
内容的提问来源于stack exchange,提问作者Sergey
相关产品推荐
相关产品推荐

