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

如何让TypeScript通过嵌套type.name正确推断联合类型对象?

问题:TypeScript嵌套字段type.name无法触发类型守卫

尝试通过判断嵌套的type.name字段,让TypeScript在switch语句中推断对象的正确类型,但无法实现类型守卫;直接判断顶层name字段时则能正常工作。希望通过type.name的值让TS识别对象可访问的属性,已知as类型断言或平铺对象的解决方案,寻求其他替代方案。

代码示例

interface Base {
  id: number;
  name:  "a" | "b" | "c" | "d"; // 此处类型守卫正常工作
  type: {
    id: number;
    name: "a" | "b" | "c" | "d"; // 此处类型守卫无法正常工作
  }
}

interface A extends Base {
  name: "a";
  type: {
    id: number;
    name: "a";
  }
  a: {
    b: number;
  }
}

interface B extends Base {
  name: "b";
  type: {
    id: number;
    name: "b";
  }
  b: {
    a: number;
  }
}

interface Generic extends Base {
  name: "c" | "d";
  type: {
    id: number;
    name: "c" | "d";
  }
}

type C = A | B | Generic

function test(t: C) {
  // 如果将switch条件改为't.name'则正常工作
  switch(t.type.name) {
  // switch(t.name) {
    case "a":
      // 期望推断为A类型,但当前无法实现
      console.log(t.a)
      break;
    case "c":
      console.log(t.name);
      break;
    case "b":
      // 期望推断为B类型,但当前无法实现
      console.log(t.b);
      break;
  }
}

解决方案

1. 自定义类型守卫函数

编写专门的类型守卫函数,明确判断type.name并返回类型断言,让TypeScript识别对象类型:

function isA(t: C): t is A {
  return t.type.name === "a";
}

function isB(t: C): t is B {
  return t.type.name === "b";
}

function test(t: C) {
  switch(t.type.name) {
    case "a":
      if (isA(t)) {
        console.log(t.a); // 正确推断为A类型
      }
      break;
    case "b":
      if (isB(t)) {
        console.log(t.b); // 正确推断为B类型
      }
      break;
    case "c":
      console.log(t.name);
      break;
  }
}

2. 重构类型定义,让type成为可辨识联合

调整类型结构,将type字段定义为联合类型,使其成为可辨识联合的一部分,这样TypeScript能直接通过type.name触发类型守卫:

// 先定义独立的type联合类型
type TypeA = { id: number; name: "a" };
type TypeB = { id: number; name: "b" };
type TypeGeneric = { id: number; name: "c" | "d" };

// 用泛型Base关联name和type的类型
interface Base<T> {
  id: number;
  name: T extends TypeA ? "a" : T extends TypeB ? "b" : "c" | "d";
  type: T;
}

interface A extends Base<TypeA> {
  a: { b: number };
}

interface B extends Base<TypeB> {
  b: { a: number };
}

interface Generic extends Base<TypeGeneric> {}

type C = A | B | Generic

function test(t: C) {
  switch(t.type.name) {
    case "a":
      console.log(t.a); // 自动推断为A类型
      break;
    case "b":
      console.log(t.b); // 自动推断为B类型
      break;
    case "c":
      console.log(t.name);
      break;
  }
}

3. 结合多字段判断触发类型推断

利用TypeScript的交叉类型推断特性,同时判断name和type.name字段(因为A/B类型中这两个字段值一致),让TS自动识别对象类型:

function test(t: C) {
  switch(t.type.name) {
    case "a":
      if (t.name === "a") {
        console.log(t.a); // 推断为A类型
      }
      break;
    case "b":
      if (t.name === "b") {
        console.log(t.b); // 推断为B类型
      }
      break;
    case "c":
      console.log(t.name);
      break;
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 09:40:42