如何在TypeScript的switch语句中正确为多个类实现类型守卫?
在TypeScript中用Switch语句实现类的联合类型守卫
方案一:使用可辨识联合(推荐)
给每个类添加一个唯一的字面量类型属性,让TypeScript能自动识别所有可能的类型分支,无需default分支也不会报错:
class A { readonly type: 'A' = 'A'; } class B { readonly type: 'B' = 'B'; } class C { readonly type: 'C' = 'C'; } type OneOfThem = A | B | C; function test(foo: OneOfThem): string { switch(foo.type) { case 'A': return "A"; case 'B': return "B"; case 'C': return "C"; // TypeScript会自动检测所有分支已覆盖,无需default } }
这种方式利用了TypeScript的可辨识联合类型特性,每个类的type属性是唯一的字面量,TS能精准推断所有可能的情况,因此不会抛出缺少return语句的错误。
方案二:结合instanceof与never断言
如果不想给类添加额外属性,可以用instanceof做类型判断,但需要配合never类型断言让TS确认所有分支已覆盖:
class A {} class B {} class C {} type OneOfThem = A | B | C; function test(foo: OneOfThem): string { switch(true) { case foo instanceof A: return "A"; case foo instanceof B: return "B"; case foo instanceof C: return "C"; default: // 用never断言告诉TS此处不会执行到,若新增类型会触发编译错误 const _unreachable: never = foo; throw new Error(`未知类型: ${_unreachable}`); } }
为什么你之前的方案无效?
- 直接用
foo.constructor作为switch表达式:TS无法推断foo.constructor的类型是确切的构造函数,联合类型下的constructor是多个构造函数的联合,TS无法确认每个case都覆盖了所有可能,因此仍会认为存在未处理的分支。 - 直接在case中写
instanceof:switch的case要求是常量表达式,foo instanceof A是布尔表达式,不能直接作为case值,所以这种写法本身语法就不合法。
内容的提问来源于stack exchange,提问作者Ettapp
相关产品推荐
相关产品推荐

