枚举
枚举(Enum)类型用来取值被限定在一定范围内的场景,比如一周只能偶七天,颜色限定为红绿蓝等。
简单的例子
枚举使用enum
关键字来定义:
enum Days { Sun, Mon, Tue, Wed, Thu, Fri, Sat };
console.log(Days["Sun"] === 0); // true
console.log(Days["Mon"] === 1); // true
console.log(Days["Tue"] === 2); // true
console.log(Days["Sat"] === 6); // true
console.log(Days[0] === "Sun"); // true
console.log(Days[1] === "Mon"); // true
console.log(Days[2] === "Tue"); // true
console.log(Days[6] === "Sat"); // true
枚举成员会被赋值从0
开始递增的数字,同时也会对枚举值到枚举名进行反向映射。
编译结果:
var Days = void 0;
(function (Days) {
Days[Days["Sun"] = 0] = "Sun";
Days[Days["Mon"] = 1] = "Mon";
Days[Days["Tue"] = 2] = "Tue";
Days[Days["Wed"] = 3] = "Wed";
Days[Days["Thu"] = 4] = "Thu";
Days[Days["Fri"] = 5] = "Fri";
Days[Days["Sat"] = 6] = "Sat";
})(Days || (Days = {}));
手动赋值
我们也可以给枚举项手动赋值:
enum Days { Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat };
上例子中,未手动赋值的枚举项会接着上一个枚举项递增。
编译结果:
(function (Days) {
Days[Days["Sun"] = 7] = "Sun";
Days[Days["Mon"] = 1] = "Mon";
Days[Days["Tue"] = 2] = "Tue";
Days[Days["Wed"] = 3] = "Wed";
Days[Days["Thu"] = 4] = "Thu";
Days[Days["Fri"] = 5] = "Fri";
Days[Days["Sat"] = 6] = "Sat";
})(Days || (Days = {}));
如果未手动赋值的枚举项和手动赋值的重复了, TypeScript是不会察觉到这一点的:
enum Days { Sun = 3, Mon = 1, Tue, Wed, Thu, Fri, Sat };
编译结果:
var Days = void 0;
(function (Days) {
Days[Days["Sun"] = 3] = "Sun";
Days[Days["Mon"] = 1] = "Mon";
Days[Days["Tue"] = 2] = "Tue";
Days[Days["Wed"] = 3] = "Wed";
Days[Days["Thu"] = 4] = "Thu";
Days[Days["Fri"] = 5] = "Fri";
Days[Days["Sat"] = 6] = "Sat";
})(Days || (Days = {}));
上例子中,递增到3
的时候与前面的Sun
取值重复了,但是 TypeScript
并没有报错,导致Days[3]
的值显示Sun
,而后又被Wed
覆盖了。
所以使用的时候需要注意,最好不要出现这种覆盖的情况。
手动赋值的枚举项也可以不是数字,此时需要使用类型断言来让tsc无视类型检查。
enum Days { Sun = 3, Mon = 1, Tue, Wed, Thu, Fri, Sat = <any> "s" };
编译结果:
var Days = void 0;
(function (Days) {
Days[Days["Sun"] = 3] = "Sun";
Days[Days["Mon"] = 1] = "Mon";
Days[Days["Tue"] = 2] = "Tue";
Days[Days["Wed"] = 3] = "Wed";
Days[Days["Thu"] = 4] = "Thu";
Days[Days["Fri"] = 5] = "Fri";
Days[Days["Sat"] = "s"] = "Sat";
})(Days || (Days = {}));
这种后续的枚举类型必须是手动赋值的:
enum Days { Sun = 3, Mon = 1, Tue, Wed, Thu = <any> "T", Fri, Sat}; //Fri, Sa 枚举成员必须具有初始化表达式。
当然手动赋值的枚举项也可以为小数或负数,此时后续未手动赋值的项递增的步长仍为1
:
enum Days { Sun = 3, Mon = 1.2, Tue, Wed, Thu, Fri, Sat };
编译结果:
var Days = void 0;
(function (Days) {
Days[Days["Sun"] = 3] = "Sun";
Days[Days["Mon"] = 1.2] = "Mon";
Days[Days["Tue"] = 2.2] = "Tue";
Days[Days["Wed"] = 3.2] = "Wed";
Days[Days["Thu"] = 4.2] = "Thu";
Days[Days["Fri"] = 5.2] = "Fri";
Days[Days["Sat"] = 6.2] = "Sat";
})(Days || (Days = {}));
常数项和计算所得项
枚举项有两种类型:常数项(constant member)和计算所得项(computed member)。
前面我们所举的例子都是常数项,下面是一个计算所得项的例子:
enum Colors { Red , Green ,Blue = 'blue'.length }
上面例子中,'blue'.length
就是一个计算所得项。
上面例子不会报错,但是如果紧接在计算所得项后面的是未手动赋值的项,那么它就会因为无法获得初始值而报错。
常数项和计算所得项的完整定义:
当满足以下条件的时候,枚举成员被当做是常数:
- 不具有初始化函数并且之前的枚举成员是常数。在这种情况下,当前枚举成员的值为上一个枚举成员的值加1,但第一个枚举元素列外。如果他没有初始化方法,那么他的初始化值为
0
。 - 枚举成员使用常数枚举表达式初始化。常数枚举的表达式 TypeScript表达式的子集,他可以在编译阶段求职。当一个表达满足下面条件之一时,他就是一个常数枚举表达式:
- 数字字面量
- 引用之前定义的常数枚举成员(可以是在不同的枚举类型中定义的),如果这个成员是在同一个枚举类型中订购一的,可以使用非限定名来引用。
- 带括号的常数枚举表达式
+
、-
、~
一元运算符应用于常数枚举表达式+
、-
、*
、/
、%
、<<
、>>
、>>>
、&
、|
、^
二元运算符,常数枚举表达式作为其一个操作对象。若常数枚举表达式求值后为NaN或Infinity,则会在编译阶段报错。
所有其他情况的没救成员被当做是需要计算得出的值。
常数枚举
常数枚举是使用const enum
定义的枚举类型:
const enum Directives{
Up,
Down,
Left,
Right
}
let directives = [Directives.Up,Directives.Down,Directives.Left,Directives.Right]
常数枚举与普通枚举的区别是,他会在编译阶段被删除,并且不能包好计算成员。
编译结果:
var directives = [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */];
假如包含了计算成员,则会在编译阶段报错。
外部枚举
外部枚举(Ambient Enums)是使用declare enum
定义的枚举类型:
declare enum Directives{
Up,
Down,
Left,
Right
}
let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
之前提到过,declare
定义的类型指挥用于编译时的检查,编译结果中会被删除。
上面的编译结果:
var directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
外部枚举与声明语句一样,常出现在声明文件中。
同时使用declare
和const
也是可以的:
declare const enum Directions {
Up,
Down,
Left,
Right
}
let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
编译结果:
var directions = [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */];