Enums
枚举允许我们定义一系列命名变量。TypeScript提拱基于数值和基于串的枚举。
数值枚举
我们从数值枚举开始。使用enum关键字来定义枚举。
这里,我们定义了一个数值枚举,并将Up的值初始化为1。后面的所有成员的值依次增1。即Down为2,Left为3,Right为4。
也可以完全不要初始化:
这里,Up的值为0,Down值为1,依次类推。这种枚举值自增的机制在我们不在意值本身是多少而只在意值是不同的情况下是很有用的。
枚举的使用是很简单的:就像访问enum自己的属性一样来使用枚举的成员, 使用枚举的名字来声明某变量是某枚举类型。
|
|
数值枚举可混用计算值和常量值(来初始化)。简单的说,没有初始化的枚举值要么定义在前面,要么定义在由数值常量初始化后的枚举值后。换句话说,下面这样声明枚举是不行的:
|
|
串枚举
字符串枚举是一个类似的概念,但在运行时有点微妙的不同,如下所述。在字符串枚举中,每个成员必须要用串字面量或另一个串枚举来初始化
|
|
尽管串枚举没有自增机制,但串枚举值有意义明确的优势。换句话说,如果你在调试代码,你就不得不读那些意义不明的数值枚举,这些值不能传递出有意义的信息(通过反向映射可能会有用),而使用串枚举就会给你一个清晰的、可读的值,和枚举成员的名字无关。
Heterogeneous enums
从技术上讲,枚举可混用串和数值值。但除非你真的想以一种聪明的方式利用JavaScript运行时,否则别这样:
|
|
计算值成员和常量成员
每个枚举成员有一个相关的值,这个值可是计算值(computed)和常量。枚举成员有下列情况的,该枚举成员是常量:
是第一个成员并且没有初始化,这时其值是0:
12// E.X is constant:enum E { X }没有初始化,并前一个枚举成员是数值储量。这时,该枚举成员的值是前一个枚举成员的值加一。
1234567// All enum members in 'E1' and 'E2' are constant.enum E1 { X, Y, Z }enum E2 {A = 1, B, C}
- 使用常量枚举表达式初始化的成员。常量枚举表达式是TypeScript表达式的一个子集,可在编译时被求解。下面都是枚举常量表达式:
- 字面量枚举表达式(串字面量或数值字面量)
- 对前面定义的常量枚举成员的引用
- 应用一元运算符
+,-,~于枚举表达式 - 二元运算符
+,-,*,/,%,<<,>>,>>>,&,|,^应用与两个常量枚举
如果表达式的值计算出来是NaN或Infinity将得到一个编译是错误。
其它的枚举即为计算值
Union enums and enum member types
一个字面量枚举成员是一个没初始化的常枚举成员
any string literal (e.g. “foo”, “bar, “baz”)
any numeric literal (e.g. 1, 100)
a unary minus applied to any numeric literal (e.g. -1, -100)
When all members in an enum have literal enum values, some special semantics come to play.
The first is that enum members also become types as well! For example, we can say that certain members can only have the value of an enum member:
The other change is that enum types themselves effectively become a union of each enum member. While we haven’t discussed union types yet, all that you need to know is that with union enums, the type system is able to leverage the fact that it knows the exact set of values that exist in the enum itself. Because of that, TypeScript can catch silly bugs where we might be comparing values incorrectly. For example:
enum E {
Foo,
Bar,
}
function f(x: E) {
if (x !== E.Foo || x !== E.Bar) {
// ~~~
// Error! Operator ‘!==’ cannot be applied to types ‘E.Foo’ and ‘E.Bar’.
}
}
In that example, we first checked whether x was not E.Foo. If that check succeeds, then our || will short-circuit, and the body of the ‘if’ will get run. However, if the check didn’t succeed, then x can only be E.Foo, so it doesn’t make sense to see whether it’s equal to E.Bar.
运行时的枚举
枚举在运行时以对象的方式存在,例如:
这个枚举E可作为参数传递给下面的函数。
逆向映射
除了为枚举创建了一个带属性的对象,数值属性也有一个从值到枚举名字的逆向映射。例如,下面的例子:
TypeScript可能会把这段代码编译成下面的JavaScript:
在这段产生的代码中,一个枚举被编译成了一个对象,该对象保存了两个方向的映射(name -> value) 和 (value -> name)。对枚举成员的访问总是被编译成对属性的访问而不是将其值内联。
记住,串枚举没有逆向映射。
常枚举 const enums
大多数情况下,枚举是一个很好的解决方案,然而有时候条件更为苛刻。为了避免编译后代码的额外开销,则可以使用常枚举。常枚举使用const修饰符来定义。
常枚举只能有常枚举表达式(作其成员),和普通枚举不同的是常枚举会在编译时被内联到使用的地方。这只有在常枚举没有计算值的才是可能的。
|
|
产生的代码为:
Ambient enums
Ambient 枚举用来描述已经存在的枚举类型
ambient枚举和非ambient枚举的一个重要的不同是那些没有初始化的成员,如果其前一个成员是常量值成员,它也将被看作常量成员。相反,一个没有初始化的ambient枚举成员将被看作是计算值成员。