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

枚举的类型

数字枚举 Numeric enums

  1. export enum Day {
  2. Monday = 1,
  3. Tuesday = 2,
  4. Wednesday = 3,
  5. Thursday = 4,
  6. Friday = 5,
  7. Saturday = 6,
  8. Sunday = 7,
  9. }

如果没有赋值,它们的值默认为数字类型且从 0 开始累加。

字符串枚举 String enums

  1. enum Direction {
  2. Up = "UP",
  3. Down = "DOWN",
  4. Left = "LEFT",
  5. Right = "RIGHT",
  6. }

异构枚举 Heterogeneous enums

数字类型和字符串类型可以混合使用,但是不建议:

  1. enum BooleanLikeHeterogeneousEnum {
  2. No = 0,
  3. Yes = "YES",
  4. }

枚举成员

计算成员和常量成员 Computed and constant members

  1. enum FileAccess {
  2. // constant members
  3. None,
  4. Read = 1 << 1,
  5. Write = 1 << 2,
  6. ReadWrite = Read | Write,
  7. // computed member
  8. G = "123".length,
  9. }

Union enums and enum member types

运行时和编译时

枚举在运行时 Enums at runtime

枚举是在运行时真正存在的对象,可以被传递到方法中:

  1. enum E {
  2. X,
  3. Y,
  4. Z,
  5. }
  6. function f(obj: { X: number }) {
  7. return obj.X;
  8. }
  9. // works, E含有X属性
  10. f(E);

枚举在编译时 Enums at compile time

即使枚举是在运行时存在的真实对象,关键字 keyof 与对象的运行方式又是不同的。我们使用 keyof typeof 来获得一个将所有Enum键表示为字符串的类型。

  1. enum LogLevel {
  2. ERROR,
  3. WARN,
  4. INFO,
  5. DEBUG,
  6. }
  7. /**
  8. * This is equivalent to:
  9. * type LogLevelStrings = 'ERROR' | 'WARN' | 'INFO' | 'DEBUG';
  10. */
  11. type LogLevelStrings = keyof typeof LogLevel;
  12. function printImportant(key: LogLevelStrings, message: string) {
  13. const num = LogLevel[key];
  14. if (num <= LogLevel.WARN) {
  15. console.log("Log level key is:", key);
  16. console.log("Log level value is:", num);
  17. console.log("Log level message is:", message);
  18. }
  19. }
  20. printImportant("ERROR", "This is a message");

正向映射和反向映射

数字枚举成员具有反向映射:

enum Enum {
  A,
}

let a = Enum.A; // 0
let nameOfA = Enum[a]; // "A"

TypeScript可能会将这段代码编译为下面的JavaScript:

"use strict";
var Enum;
(function (Enum) {
    Enum[Enum["A"] = 0] = "A";
})(Enum || (Enum = {}));
let a = Enum.A;
let nameOfA = Enum[a]; // "A"

生成的代码中,枚举类型被编译成一个对象,它包含了正向映射( name -> value)和反向映射( value -> name)。
要注意的是:不会为字符串枚举成员生成反向映射。

枚举的定义

enum

当我们定义一个枚举

enum Cheese { Brie, Cheddar }

编译器将编译为:

var Cheese;
(function (Cheese) {
    Cheese[Cheese["Brie"] = 0] = "Brie";
    Cheese[Cheese["Cheddar"] = 1] = "Cheddar";
})(Cheese || (Cheese = {}));

所以我们可以正向映射或反向映射:

// Evaluates to 0 at runtime
Cheese.Brie;
// Evaluates to 'Brie' at runtime
Cheese[0];

const enum

当我们定义一个const枚举:

const enum Bread { Rye, Wheat }

不会有任何代码编译输出。只有当我们访问:

const rye = Bread.Rye
// or
const rye = Bread['Rye']

只剩下常量 rye。当如果你访问:

// Compiler error. const enums don't provide reverse lookup.
// Bread[0]

运行时就会报错。

Note:如果tsconfig 打开配置项 --preserveConstEnums ,编译结果将会和定义普通enum一样。

declare enum

官方文档也叫 Ambient enums

定义一个外部枚举:

declare enum Wine { Red, Wine }

也不会编译出任何代码。它是用来描述已经存在的枚举类型的形状。

declare const enum

declare const enum Fruit { Apple, Pear }

Objects vs Enums

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

const ODirection = {
  Up: 0,
  Down: 1,
  Left: 2,
  Right: 3,
} as const;

EDirection.Up;
//         ^ = (enum member) EDirection.Up = 0

ODirection.Up;
//         ^ = (property) Up: 0

// Using the enum as a parameter
function walk(dir: EDirection) {}

// It requires an extra line to pull out the keys
type Direction = typeof ODirection[keyof typeof ODirection];
function run(dir: Direction) {}

walk(EDirection.Left);
run(ODirection.Right);

参考: