枚举类 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 枚举
待后期学习