TypeScript 学习笔记(九):枚举类型

2 阅读4分钟

前言

在上一篇文章TypeScript 学习笔记(八):类型断言中我们学习了TS中的类型断言,本篇文章我们主要了解TS中的枚举类型

如果你也和我一样在为大厂冲刺的话,欢迎添加我的微信lx3122178991,这里有一群小伙伴有着和你同样的目标,欢迎来一起讨论,一同进步。

枚举是什么

枚举是一个被命名的整型常数的集合,用于声明一组命名的常数,当一个变量有几种可能的取值时,可以将它定义为枚举类型。通俗来说,枚举就是一个对象的所有可能取值的集合。

枚举的基本使用

在 TypeScript 中,我们可以使用 enum 关键字来定义枚举类型。例如:

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

上面的代码定义了一个名为 Direction 的枚举类型,它包含了四个成员:UpDownLeftRight。默认情况下,枚举成员的值从 0 开始依次递增,即 Up 的值为 0,Down 的值为 1,以此类推。

如果只设定第一个成员的值,后面成员的值就会从这个值开始递增。

enum Color {
  Red = 7,
  Green,  // 8
  Blue   // 9
}

// 或者
enum Color {
  Red, // 0
  Green = 7,
  Blue // 8
}

枚举成员的值可以是任意数值,但不能是大整数(Bigint)。

enum Color {
  Red = 90,
  Green = 0.5,
  Blue = 7n // 报错
}

枚举成员的值可以相同。

enum Color {
  Red = 0,
  Green = 0,
  Blue = 0
}

枚举成员的值也可以使用计算式。

enum Permission {
  UserRead     = 1 << 8,
  UserWrite    = 1 << 7,
  UserExecute  = 1 << 6,
  GroupRead    = 1 << 5,
  GroupWrite   = 1 << 4,
  GroupExecute = 1 << 3,
  AllRead      = 1 << 2,
  AllWrite     = 1 << 1,
  AllExecute   = 1 << 0,
}

enum Bool {
  No = 123,
  Yes = Math.random(),
}

Enum 成员值都是只读的,不能重新赋值。

enum Color {
  Red,
  Green,
  Blue
}

Color.Red = 4; // 报错

枚举的合并 

同名的枚举结构会自动合并。

enum Foo {
  A,
}

enum Foo {
  B = 1,
}

enum Foo {
  C = 2,
}

// 等同于
enum Foo {
  A,
  B = 1,
  C = 2
}

枚举结构合并时,只允许其中一个的首成员省略初始值,否则报错。

enum Foo {
  A,
}

enum Foo {
  B, // 报错
}

枚举合并时,不能有同名成员,否则报错。

enum Foo {
  A,
  B
}

enum Foo {
  B = 1, // 报错
  C
}

枚举类型有几种

枚举类型可以分成这三种:

  • 数字枚举
  • 字符串枚举
  • 异构枚举

数字枚举

当我们声明一个枚举类型是,虽然没有给它们赋值,但是它们的值其实是默认的数字类型,而且默认从0开始依次累加:

enum Direction {
    Up,   // 值默认为 0
    Down, // 值默认为 1
    Left, // 值默认为 2
    Right // 值默认为 3
}

console.log(Direction.Up === 0); // true
console.log(Direction.Down === 1); // true
console.log(Direction.Left === 2); // true
console.log(Direction.Right === 3); // true

字符串枚举

枚举类型的值可以是字符串类型:

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

如果设定了一个变量为字符串之后,后续的字段也需要赋值字符串,否则报错:

enum Direction {
 Up = 'UP',
 Down, // error TS1061: Enum member must have initializer
 Left, // error TS1061: Enum member must have initializer
 Right // error TS1061: Enum member must have initializer
}

异构枚举

异构枚举就是将数字枚举和字符串枚举结合起来混合起来使用。

enum BooleanLikeHeterogeneousEnum {
    No = 0,
    Yes = "YES",
}

反向映射

数值枚举存在反向映射,即可以通过成员值获得成员名。

enum Weekdays {
  Monday = 1,
  Tuesday,
  Wednesday,
  Thursday,
  Friday,
  Saturday,
  Sunday
}

console.log(Weekdays[3]) // Wednesday

上面示例中,Enum 成员Wednesday的值等于3,从而可以从成员值3取到对应的成员名Wednesday,这就叫反向映射。

这是因为TS会将上面的枚举结构,编译成下面的JS代码。

var Weekdays;
(function (Weekdays) {
    Weekdays[Weekdays["Monday"] = 1] = "Monday";
    Weekdays[Weekdays["Tuesday"] = 2] = "Tuesday";
    Weekdays[Weekdays["Wednesday"] = 3] = "Wednesday";
    Weekdays[Weekdays["Thursday"] = 4] = "Thursday";
    Weekdays[Weekdays["Friday"] = 5] = "Friday";
    Weekdays[Weekdays["Saturday"] = 6] = "Saturday";
    Weekdays[Weekdays["Sunday"] = 7] = "Sunday";
})(Weekdays || (Weekdays = {}));

上面代码中,实际进行了两组赋值,以第一个成员为例。

Weekdays[
  Weekdays["Monday"] = 1
] = "Monday";

//实际等同于
Weekdays["Monday"] = 1;
Weekdays[1] = "Monday";

注意,这种情况只发生在数值枚举,对于字符串枚举,不存在反向映射。这是因为字符串枚举编译后只有一组赋值。

enum MyEnum {
  A = 'a',
  B = 'b'
}

// 编译后
var MyEnum;
(function (MyEnum) {
    MyEnum["A"] = "a";
    MyEnum["B"] = "b";
})(MyEnum || (MyEnum = {}));