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
相关产品推荐
相关产品推荐

