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

TypeScript如何实现联合类型收窄 正确访问不同类型独有属性

问题原因

该报错的本质是:当联合类型的多个分支没有公共可辨识字段时,TypeScript 静态检查阶段不会允许直接访问仅存在于单个分支上的属性,必须通过类型收窄让编译器确认参数的具体子类型,才能获得正确的类型推导。这个场景不需要使用泛型,通过TS内置的类型守卫能力即可实现。

实现方案

方案1:使用in操作符收窄(无需修改原有类型定义)

in是TS内置的类型守卫语法,通过判断属性是否存在于对象上,自动将联合类型收窄到匹配的分支,正好匹配你“存在options属性就是A类型,不存在就是B类型”的判断逻辑:

type Options = {
  items: Array<string>;
};
type A = {
  options: Options;
  a: string;
};

type B = {
  b: number;
};

type AB = A | B;

function test(p: AB) {
  // 判断options属性是否存在,TS自动收窄类型
  if ('options' in p) {
    // 此分支内p被推导为A类型,可安全访问options、a属性
    console.log(p.options.items, p.a);
  } else {
    // 此分支内p被推导为B类型,可安全访问b属性
    console.log(p.b);
  }
}

如果需要通过a、b属性判断,也可以直接写if ('a' in p)/if ('b' in p),效果一致。

方案2:定义可辨识联合类型(复杂场景推荐)

如果后续联合类型的分支会扩展,推荐给每个类型加一个固定的字面量标识字段,构成可辨识联合,这是TS中联合类型的最佳实践:

type Options = {
  items: Array<string>;
};
// 给每个类型加唯一的type字面量字段作为标识
type A = {
  type: 'a';
  options: Options;
  a: string;
};

type B = {
  type: 'b';
  b: number;
};

type AB = A | B;

function test(p: AB) {
  // 通过判断type字段值收窄类型
  switch(p.type) {
    case 'a':
      // 此分支p类型为A
      console.log(p.options.items, p.a);
      break;
    case 'b':
      // 此分支p类型为B
      console.log(p.b);
      break;
  }
}

方案3:自定义类型守卫(需要封装判断逻辑时使用)

如果判断A/B类型的逻辑比较复杂,可以封装自定义类型守卫函数,通过is语法告诉TS类型判断的结果:

// 返回值p is A 表示:函数返回true时,p的类型为A
function isTypeA(p: AB): p is A {
  // 这里可以写自定义的判断逻辑,比如判断options是否是对象、items是否为数组等
  return typeof (p as A).a === 'string' && !! (p as A).options;
}

function test(p: AB) {
  if (isTypeA(p)) {
    // 此分支p类型为A
    console.log(p.options.items, p.a);
  } else {
    // 此分支p类型为B
    console.log(p.b);
  }
}
注意事项

不要直接写if(p.a)/if(p.b)做判断:在类型没有收窄的前提下,TS静态检查时会认为AB类型上不存在a/b属性,直接抛出编译错误,必须先通过上述三种方式完成类型收窄,才能访问对应类型的独有属性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 17:39:20