You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何使用对象键取值时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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 20:55:19