跳到主要内容

枚举类 Enums

数值枚举类

枚举类可以用 enum 来定义:

enum Direction {
Up = 1,
Down,
Left,
Right,
}

在上面的例子中,虽然我们只定义 Up 背后的数值为 1 ,但是 DownLeftRight 也会被自动代表数值 234

如果你没有给 Up 定义数值,那么四个枚举成员将自动代表 0123

字符串枚举类

在字符串枚举中,每个枚举成员都要给定一个字符串字面量,或者是另一个字符串枚举的成员:

enum Direction {
Up = 'UP',
Down = 'DOWN',
Left = 'LEFT',
Right = 'RIGHT',
}

不同的枚举成员可以有相同的值。

::: tip 含多种类型的枚举 技术上你可以混合数值或字符串类型的枚举,但是这是十分不建议的。除非你很了解你在做什么。 :::

计算与常量型成员

在上述的例子中,我们都是将字面量,也就是常量赋值给枚举成员。我们称这类为常量型成员,它们在编译阶段便确定好了值。以下这几种情况都视为常量型成员:

  • 字面量
  • 别的枚举类型的常量型枚举成员
  • 带括号的常量表达式
  • +-~ 一元常量表达式
  • +-*/%<<>>>>>&|^ 位运算常量表达式

以上情况如果在编译阶段出现错误将赋值为 NaNInfinity

对于其他情况都将视为计算型成员,只有数字类型可以作为计算型成员的枚举值:

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 枚举

待后期学习