枚举类 Enums
数值枚举类
枚举类可以用 enum
来定义:
enum Direction {
Up = 1,
Down,
Left,
Right,
}
在上面的例子中,虽然我们只定义 Up
背后的数值为 1
,但是 Down
、Left
、Right
也会被自动代表数值 2
、3
、4
。
如果你没有给 Up
定义数值,那么四个枚举成员将自动代表 0
、1
、2
、3
。
字符串枚举类
在字符串枚举中,每个枚举成员都要给定一个字符串字面量,或者是另一个字符串枚举的成员:
enum Direction {
Up = 'UP',
Down = 'DOWN',
Left = 'LEFT',
Right = 'RIGHT',
}
不同的枚举成员可以有相同的值。
::: tip 含多种类型的枚举 技术上你可以混合数值或字符串类型的枚举,但是这是十分不建议的。除非你很了解你在做什么。 :::
计算与常量型成员
在上述的例子中,我们都是将字面量,也就是常量赋值给枚举成员。我们称这类为常量型成员,它们在编译阶段便确定好了值。以下这几种情况都视为常量型成员:
- 字面量
- 别的枚举类型的常量型枚举成员
- 带括号的常量表达式
+
、-
、~
一元常量表达式+
、-
、*
、/
、%
、<<
、>>
、>>>
、&
、|
、^
位运算常量表达式
以上情况如果在编译阶段出现错误将赋值为 NaN
或 Infinity
。
对于其他情况都将视为计算型成员,只有数字类型可以作为计算型成员的枚举值:
enum FileAccess {
// 常量型成员
None,
Read = 1 << 1,
Write = 1 << 2,
// 计算型成员
G = '123'.length,
}
枚举型成员及联合特性
我们称以下几种情况为枚举字面量,同时称此类成员为枚举型成员:
- 无初始化
- 任何的字符串或数值字面量
- 带一元操作符的数值字面量(比如
-1
)
同时,枚举型成员自身可以表示成类型,同时其自身也是该类型的唯一合法值:
enum ShapeKind {
Circle,
Square,
}
interface Circle {
kind: ShapeKind.Circle;
radius: number;
}
let c: Circle = {
// ERROR: `ShapeKind.Square` 不能赋值给 `ShapeKind.Circle` 类型
kind: ShapeKind.Square,
radius: 100,
};
另一个特性是,枚举类自身会成为一个包含其下所有枚举型成员的联合类型。因此,这类枚举类将拥有联合类型的检查功能,比如:
enum E {
Foo,
Bar,
}
function f(x: E) {
// ERROR: 这个表达式会永远成真,因为两个类型 `E.Foo`、`E.Bar` 没有发生重叠
if (x !== E.Foo || x !== E.Bar) {
// ...
}
}
运行时中的枚举类
枚举自身在运行时是一个真实的对象,你可以当参数传递给函数:
enum E {
X,
Y,
Z,
}
function f(obj: { X: number }) {
return obj.X;
}
// 可以成功调用,`E` 有一个类型为 `number` 的属性 `X`
f(E);
编译阶段的枚举类
待后期学习
逆向映射
数值枚举型成员可以通过逆向映射来获取其成员名称:
enum Enum {
A,
B,
C,
}
let a = Enum.A;
let nameOfA = Enum[a]; // "A"
TypeScript 会将其编译成下面 JavaScript 代码:
var Enum;
(function (Enum) {
Enum[(Enum['A'] = 0)] = 'A';
Enum[(Enum['B'] = 1)] = 'B';
Enum[(Enum['C'] = 2)] = 'C';
})(Enum || (Enum = {}));
var a = Enum.A;
var nameOfA = Enum[a]; // "A"
注意,字符串枚举型成员没有这项特性。
const
枚举类
一些严格的需求下,我们可能需要摒弃编译之后枚举类所带来的冗余代码。这个时候我们可以用 const
去修饰 enum
。常量枚举类只能使用常量枚举表达式,比如:
const enum Direction {
Up,
Down,
Left,
Right,
}
let directions = [
Direction.Up,
Direction.Down,
Direction.Left,
Direction.Right,
];
会被编译成:
'use strict';
let directions = [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */];
Ambient 枚举类
待后期学习
对象 vs 枚举
待后期学习