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

使用带索引签名的联合类型时TypeScript报属性不存在错误

TypeScript索引签名场景下的类型收窄失效问题

场景重现

先定义基础接口:

interface A {
  type: 'A';
  value: {
    a: 3;
  };
}

interface B {
  type: 'B';
  value: {
    b: 3;
  };
}

interface C {
  detail: A | B;
}

当直接使用C类型时,通过type属性可以正常完成类型收窄,代码无报错:

function test(arg: C) {
  if (arg.detail.type === 'A') {
    arg.detail.value.a; // 类型已收窄为A,可正常访问a属性
  } else if (arg.detail.type === 'B') {
    arg.detail.value.b; // 类型已收窄为B,可正常访问b属性
  }
}

异常场景

当创建带索引签名的接口cArr后:

interface cArr {
  [index: string]: C;
}

尝试通过索引访问并收窄类型时,TypeScript抛出错误:

function test(arg2: cArr, ID: string) {
  if (arg2[ID].detail.type === 'A') {
    arg2[ID].detail.value.a; // 此处报错
  }
}

报错信息:

Property 'a' does not exist on type '{ a: 3; } | { b: 3; }'.
  Property 'a' does not exist on type '{ b: 3; }'.

问题根源

  1. 索引访问的不确定性:TypeScript无法确保两次arg2[ID]访问返回的是同一个值。因为带索引签名的对象允许动态修改属性,理论上在if判断和后续属性访问之间,arg2[ID]的值可能被外部代码修改,导致类型发生变化。
  2. 类型收窄的作用域限制:对于直接的变量访问(比如第一个例子里的arg.detail),TypeScript能跟踪变量的类型变化;但动态索引访问的属性会被视为独立表达式,TypeScript无法将if中的类型判断结果关联到后续的索引访问操作上。

解决方法

将索引访问的结果存入临时变量,让TypeScript能跟踪这个变量的类型变化:

function test(arg2: cArr, ID: string) {
  const currentItem = arg2[ID];
  if (currentItem.detail.type === 'A') {
    currentItem.detail.value.a; // 类型正常收窄,无报错
  }
}

通过临时变量currentItem,TypeScript可以在if判断后正确收窄其类型,从而允许访问对应的属性。

内容的提问来源于stack exchange,提问作者milad

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 14:41:34