枚举可以为定义一些带名字的常量,枚举可以清晰的表达意图,typescript支持数字枚举和字符串枚举,并且枚举是真是运行在编译后的代码中的。
数字枚举
enum sex{
man,
woman
}
sex.man; // 0
sex[0]; // 0
sex.woman; // 1
sex[1]; // 1
数字枚举是自增的,并且默认值是从0开始的和相互反向映射的
正向映射(name->value)
反向映射(value->name)
以下是编译后的代码。
var sex;
(function (sex) {
sex[sex["man"] = 0] = "man";
sex[sex["woman"] = 1] = "woman";
})(sex || (sex = {}));
并且数值可以自定义,一旦遇到自定义数值,接下来的枚举属性都从自定义值开始自增,下面这个例子可以详细证明。
enum sex{
man = 1, //自定义
woman,
boy = 5, //自定义
girl
}
/************以下是编译后的代码********************/
var sex;
(function (sex) {
sex[sex["man"] = 1] = "man";
sex[sex["woman"] = 2] = "woman";
sex[sex["boy"] = 5] = "boy";
sex[sex["girl"] = 6] = "girl";
})(sex || (sex = {}));
字符串枚举
字符串枚举和数值有细微差别,没有自增,也没有反向映射,枚举成员必须用字符串字面量,或者另外一个字符串枚举成员进行初始化。换句话说,如果你在调试数值枚举运行时的值时,这个值的可读性不高,不能表达有用的信息(尽管反向代理有所帮助),字符串枚举允许你提供一个运行时有意义的值。
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",
}
/************以下是编译后的代码********************/
var Direction;
(function (Direction) {
Direction["Up"] = "aa";
Direction["Down"] = "DOWN";
Direction["Left"] = "LEFT";
Direction["Right"] = "RIGHT";
})(Direction || (Direction = {}));
异构枚举
一个枚举可以既有字符串成员和数值成员,但并不建议这样子去做,除非有必要的javascript特殊运行时的行为。
enum BooleanLikeHeterogeneousEnum {
No = 0,
Yes = "YES",
}
枚举成员值得类型
常量 和 计算后的,常量成员需要符合三个条件
- 它是枚举第一个成员并且无初始化器
- 它不带初始化器且前一个成员是一个数字常量,此时值是上一个枚举成员+1
- 枚举成员使用常量枚举初始化,常数枚举表达式可以在编译阶段求值,满足以下条件之一,就是常数表达式
- 一个字符串字面量或者数值字面量
- 一个对之前常量枚举成员得引用(可以来自不同枚举甚至本枚举)
- 一元、二元运算符运用在常量表达式中。如果计算后为NaN和undefined则编译时报错
不满足这些条件的都属于计算得出的枚举值。
enum FileAccess {
// 常量成员
None,
Read = 1 << 1,
Write = 1 << 2,
ReadWrite = Read | Write,
// 不符合条件计算后得出的值
G = "123".length
}
联合枚举
当枚举成员成为了接口中的成员的值,那么在赋值的时候可以得到一些有消息,例如:
enum ShapeKind {
Circle,
Square,
}
interface Circle {
kind: ShapeKind.Circle;
radius: number;
}
interface Square {
kind: ShapeKind.Square;
sideLength: number;
}
let c: Circle = {
kind: ShapeKind.Square,//error,类型'ShapeKind.Square' 不可以分配给 'ShapeKind.Circle
radius: 100,
}
枚举成员本身使每个枚举成员的联合,类型系统可以知道枚举里的值,利用这个特点可以捕获比较愚蠢的错误。例如:
enum E {
Foo,
Bar,
}
function f(x: E) {
if (x !== E.Foo || x !== E.Bar) {
//这里枚举E只有两个成员,那么我们判断x !== E.Foo为true,if内逻辑执行,如果为false,那么x一定是 E.Bar,没必要继续检查是否为E.bar,所以语句后发生了短路。改为
}
}
运行时的枚举
枚举是运行时真正存在的对象,例如下面的例子
enum E {
X, Y, Z
}
console.log(E.X) //输出 0
const枚举
当使用const修饰枚举时,会跟普通的枚举有区别:不存在编译后的代码中,常量枚举成员使用的地方会被直接替换成值。
const denum E {
X = 1+1, Y, Z
}
console.log(E.X) //输出 0
/**************编译后代码*********************/
console.log(2 /* X */); //枚举相关已被删除替换
外部枚举
用来定义已经存在的枚举,使用declare来修饰枚举。外部枚举和非外部枚举之间有一个重要区别:在正常枚举里,没有初始化方法的成员被当作常数成员,而外部枚举则当作需要经过计算的。