TypeScript 的 enum 类型收窄问题
背景
在项目中看到一段小伙伴写的代码,简化后大概如下:
enum A {
"ONE" = 1,
"TWO" = 2
}
const a = Math.random() > 0.5 ? A.ONE : A.TWO
const b = Math.random() > 0.5 ? a : 0
if(b === 1 || b === 2) {
}
此时,b === 2 处 ts 会提示:
This condition will always return 'false' since the types '0' and '2' have no overlap.ts(2367)
为何 TypeScript 会提示 0 与 2 没有重合的地方呢?
分析
鼠标悬浮在 b === 1 时,提示 b 的类型为 A | 0 的联合类型,而到了 b === 2 时,却变成了 b: 0。那么也就是说 TypeScript 在判断 b !== 1 时,就判定 b 不可能为类型 A,此时将类型收窄为 0。而 0 不可能 assgin 给 2,因此报错。上网搜索似乎也没有得到为何时这种收窄策略的原因,仅有一个可能有关联的 https://github.com/Microsoft/TypeScript/issues/9998 , 然而至今还是 open 的。
解决
那我们要怎么解决这个报错呢?实际上我们将判断的右值改成 enum 即可,且逻辑更清晰,维护更简单:
if(b === A.ONE || b === A.TWO) {
// no error
}
或者下面这种也可以(不是很推荐,没有发挥出 enum 应有的作用)
if(b as A === 1 || b === 0) {
// no error
}