枚举可以定义一些带名字的常量。
使用枚举可以清晰地表达意图或创建一组有区别的用例

数字枚举

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

console.log(Direction.Left); // 3

Up初始化为 1,后面的成员会从1开始自动增长。所以 Up1Down2Left3Right4

不使用初始化,成员的值从0开始递增

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

console.log(Direction.Up); // 0
console.log(Direction.Left); // 2

字符串枚举

字符串枚举中,每个成员都必须用字符串字面量。

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

由于字符串枚举没有自增长,字符串枚举可以很好的序列化。
数字枚举的运行时的值,通常比较难读取,而且不能表达有用的信息。
字符串枚举允许你提供一个运行时有意义的并且可读的值,独立于枚举成员的名字。

异构枚举 (不推荐)

枚举可以混合字符串和数字成员

enum BooleanLikeHeterogeneousEnum {
  No = 0,
  Yes = 'Yes',
}

计算的和常量成员

每个枚举成员都带有一个值,可以是常量或计算出来的。当满足如下条件时,枚举成员被当作是常量:

  • 枚举的第一个成员且没有初始化器,这种情况下它被赋予值0
enum E {
  x,
}
  • 不带有初始化器且之前的枚举成员是一个数字常量。这种情况下,当前枚举成员的值为上一个枚举成员的值加1
enum E1 {
  X,
  Y,
  Z,
}

enum E2 {
  A = 1,
  B,
  C,
}
  • 枚举成员使用常量枚举表达式初始化。常量枚举表达式是 TypeScript 表达式的子集,可以在编译阶段求值。满足一下条件,就是一个常量枚举表达式:
  • 一个枚举表达式字面量(主要是字符串字面量或数字字面量)
  • 一个对之前定义的常量枚举成员的引用(可以是在不同的枚举类型中定义)
  • 带括号的常量枚举表达式
  • 一元运算符 +, -, ~其中之一应用在了常量枚举表达式
  • 常量枚举表达式做为二元运算符+,-,*,/,<<,>>,>>>,&,|,^的操作对象。若常数枚举表达式求值后为NaNInfinity,则会在编译阶段报错。

其他情况的枚举成员被当作是需要计算的出的值。

enum FileAccess {
  None,
  Read = 1 << 1,
  Write = 1 << 2,
  ReadWrite = Read | Write,
  // 计算 值
  G = '123'.length,
}

联合枚举与枚举成员的类型

存在一种特殊的非计算的常量枚举成员的子集:字面量枚举成员。
字面量枚举成员:指不带初始值的常量枚举成员,或者是值被初始化为

  • 任何字符串字面量 (例如:“foo”, “bar”, “baz”)
  • 任何数字字面量 (例如:1,100)
  • 应用了一元-符号的数字字面量 (例如:-1, -100)

当所有枚举成员都拥有字面量枚举值时,就带有一种特殊的语义

枚举成员称为类型

enum ShapeKind {
  Circle,
  Square,
}

interface Circle {
  kind: ShapeKind.Circle;
  radius: number;
}

interface Square {
  kind: ShapeKind.Square;
  sideLength: number;
}

let c: Circle = {
  kind: ShapeKind.Circle,
  radius: 10,
};

运行时枚举

enum E {
  X,
  Y,
  Z,
}

function f(obj: {X: number}) {
  return obj.X;
}

console.log(f(E));

反向映射

enum Enum {
  A,
}

let a = Enum.A;
let nameOfA = Enum[a];
console.log(nameOfA); // A

通过枚举值获取的枚举名

const 枚举(常量枚举)

避免在额外生成的代码上的开销和额外的非直接的对枚举成员的访问。可以使用const枚举。

const enum Enum {
  A = 1,
  B = A * 2,
}

常量枚举只能使用常量枚举表达式,并且不同于常规的枚举,在编译阶段会被删除。
常量枚举成员在使用的地方会被内联进去。常量枚举不允许包含计算成员

const enum Direction {
  Up,
  Down,
  Left,
  Right,
}

let directions = [
  Direction.Up,
  Direction.Down,
  Direction.Left,
  Direction.Right,
];

// 编译后的代码
var directions = [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */];

外部枚举

用来描述应该存在的枚举类型的形状。

  • 外部枚举和正常枚举的区别
  1. 在正常枚举里,没有初始化方法的成员被当成常数成员。
  2. 对于外部枚举里,没有初始化方法时被当作需要经过计算的
declare enum Enum {
  A = 1,
  B,
  C = 2,
}
declare enum E {
  A,
  B,
}

function f(e: E) {
  return e;
}

console.log(f(E.A)); // 无任何输出
declare const enum E {
  A,
  B,
}

function f(e: E) {
  return e;
}

console.log(f(E.A)); // 0

从上面代码运行结果看,

  • 外部枚举只有declare时候,只是个声明,在不会被编译。
  • 外部枚举只有declare const时候,不只是个声明,不会编译,但是运行阶段会获取到常量值。