TypeScript赞成使用枚举的理由是,比起直接用数字,枚举提供了更多的安全性和透明度。
enum Direction{
UP = 0,
DOWN = 1,
LEFT = 2,
RIGHT = 3
}
let direction = Direction.UP; // 类型是Direction
Direction // 自动补全显示:UP,DOWN,...
Direction[0] // 值为UP
其实,TypeScript中的枚举有几种不同的变体,它们的行为都有微妙的不同:
- 数字值的枚举。任何数字都可以分配到这个枚举,所以它不是很安全(数字值枚举可以实现标志位结构)
- 字符串值的枚举。这个确实提供了类型安全,也在运行时提供了更透明的值。但它不是结构类型化的,不像TypeScript中的任何其他类型。
- const enum。与普通枚举不同,const enum在运行时完全消失。如果你在前面的例子中改成const enum Direction,编译器会把Direction.UP改写成0。这不但打破了我们对编译器应有行为的期望,而且任然有string和number值枚举之间的分歧行为。
- 设置了preserveConstEnum标志的const enum。这将为const enum输出运行时代码,就和为普通的enum所做的一样。
字符串值的枚举是名义类型化的,这个是特别出人意料的部分,因为TypeScript中的其他类型的可分配性都用了结构类型来判断。
enum Direction{
UP = 'up',
DOWN = 'down',
LEFT = 'left',
RIGHT = 'right'
}
let direction = Direction.UP; // 类型是Direction
direction = 'right-up'; // ~~不能将类型'right-up'分配给类型Direction
当要发布一个库的时候,这就会有影响。假设需要一个Direction函数:
function toDirection(direction: Direction) { /*...*/ }
因为运行时的Deirection其实只是一个字符串,所以你的JavaScript用户可以用一个字符串来调用它:
toDirection('up'); // JavaScript中OK
但你的TypeScript用户将需要导入enum来调用它:
toDirection('up'); // ~~'up'不能分配给类型为Direction的参数
import { Direction } from 'direction';
toDirection(Direction.UP); // OK
JavaScript和TypeScript用户的这些体验的不一致性是应避免使用字符串值枚举的原因之一。TypeScript提供了一个在其他语言中不太常见的枚举的替代方案–字面量类型的联合:
type Direction = 'up' | 'down' | 'left' | 'right';
let direction: Direction = 'up'; // OK
direction = 'right-up'; // ~~不能将类型‘right-up’分配给类型Direction
它提供了和枚举一样强大的安全性,并且具有更直接地编译成JavaScript的优势。它也能在你的编译器中提供同样强大的自动补全特性。