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

TypeScript中枚举的判别属性:如何用Switch实现枚举判别联合的模式匹配?

在TypeScript中用Switch模拟模式匹配实现枚举判别联合的最简方式

你的问题出在当前的类型定义上:Fruit和Vegetable是普通枚举,它们的联合类型Grocery只是枚举值的集合(默认是数字),并没有kind这个属性,所以grocery.kind会直接报错。要实现判别式联合(也就是能让TypeScript自动收窄类型的联合),我们需要给每个品类添加一个共同的判别属性,然后基于这个属性写switch逻辑。

下面是最简的正确实现:

步骤1:定义带判别式的联合类型

首先我们把枚举和判别属性结合,做成结构化的对象类型联合:

// 保留你的枚举定义
enum Fruit { Apple, Banana, Orange }
enum Vegetable { Tomato, Carrot, Potato }

// 定义带kind判别属性的联合类型
type Grocery = 
  | { kind: "Fruit", item: Fruit }
  | { kind: "Vegetable", item: Vegetable };

这里的kind就是判别属性:每个联合成员都有这个属性,且值是唯一的字面量("Fruit"或"Vegetable"),TypeScript会通过它自动识别当前的类型分支。

步骤2:编写带类型收窄的Switch函数

接下来写你的处理函数,TypeScript会在switch分支里自动收窄grocery的类型:

// 处理水果的函数,只接收Fruit类型的Grocery
function doStuff(grocery: { kind: "Fruit", item: Fruit }) {
  // 这里还可以继续对grocery.item做枚举判断
  switch(grocery.item) {
    case Fruit.Apple:
      console.log("Got an apple!");
      break;
    case Fruit.Banana:
      console.log("Got a banana!");
      break;
    // 其他水果分支...
  }
}

// 处理蔬菜的函数
function doOtherStuff(grocery: { kind: "Vegetable", item: Vegetable }) {
  switch(grocery.item) {
    case Vegetable.Tomato:
      console.log("Got a tomato!");
      break;
    // 其他蔬菜分支...
  }
}

function checkStuff(grocery: Grocery) {
  switch (grocery.kind) {
    case "Fruit":
      doStuff(grocery); // TypeScript自动知道这里grocery是Fruit类型
      break;
    case "Vegetable":
      doOtherStuff(grocery); // 自动收窄为Vegetable类型
      break;
    default:
      // 可选:添加never断言确保覆盖所有分支,避免遗漏新类型
      const _exhaustiveCheck: never = grocery;
      throw new Error(`Unexpected grocery type: ${_exhaustiveCheck}`);
  }
}

更简化的写法(如果不需要单独枚举)

如果你的场景不需要单独的枚举类型,也可以直接用字面量联合简化定义:

type Grocery = 
  | { kind: "Fruit", name: "Apple" | "Banana" | "Orange" }
  | { kind: "Vegetable", name: "Tomato" | "Carrot" | "Potato" };

function checkStuff(grocery: Grocery) {
  switch (grocery.kind) {
    case "Fruit":
      console.log(`Handling fruit: ${grocery.name}`);
      break;
    case "Vegetable":
      console.log(`Handling vegetable: ${grocery.name}`);
      break;
    default:
      const _: never = grocery;
      throw new Error(`Unknown grocery type: ${_}`);
  }
}

关键要点

  • 判别式联合的核心是共同的字面量类型属性(比如这里的kind),它是TypeScript自动类型收窄的依据
  • Switch语句基于这个判别属性判断时,每个分支里的变量类型会被自动收窄到对应的联合成员
  • 最后的default分支加never断言是一个好习惯,可以确保当你后续给Grocery添加新成员时,TypeScript会提示你补充对应的处理逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 12:29:02