一.简介

Enum 是 TypeScript 新增的一种数据结构和类型

let student: number = 1;
let teacher: number = 2;
let clearer: number = 3;

let people: number = Math.floor(Math.random() * 3) + 1;

if (people === student) {
  console.log("学生");
}
if (people === teacher) {
  console.log("老师");
}
if (people === clearer) {
  console.log("班主任");
}

实际开发中,经常需要定义一组相关的常量来进行一些操作;

TypeScript 设计了 Enum 结构,用来将相关常量放在一个容器里面,方便使用。

// 使用枚举类型进行操作
enum People {
  student,
  teacher,
  clearer,
}

let people: People = Math.floor(Math.random() * 3) + 1;

switch (people) {
  case People.student:
    console.log("学生");
    break;
  case People.teacher:
    console.log("老师");
    break;
  case People.clearer:
    console.log("班主任");
    break;
  default:
    console.log("未知人员");
    break;
}

调用方式(两种):

enum People {
  student,
  teacher,
  clearer,
}

// 调用时,可以使用点运算符,也可以使用方括号运算符。
let p1: People = People.student;
let p2: People = People["teacher"];
console.log(p1, p2); // 1 2

结构方面,Enum 结构本身也是一种类型。就比如上面的来说:(采用People与number是一样的)

// 使用枚举类型进行操作
enum People {
  student,
  teacher,
  clearer,
}

// 类型结构方面
let p3: People = People.student; // 0
let p4: number = p3; // 0
console.log(p4); // 0

二.易出错点

由于 TypeScript 的定位是 JavaScript 语言的类型增强,所以官方建议谨慎使用 Enum 结构,因为它不仅仅是类型,还会为编译后的代码加入一个对象。

编译前的typescript代码:

// 使用枚举类型进行操作
enum People {
  student,
  teacher,
  clearer,
}

编译为JavaScript代码后:

// 使用枚举类型进行操作
var People;
(function (People) {
    People[People["student"] = 0] = "student";
    People[People["teacher"] = 1] = "teacher";
    People[People["clearer"] = 2] = "clearer";
})(People || (People = {}));

观察JavaScript代码可以看出,typescript代码编译后会变成 JavaScript 对象,留在代码中。

所以不能有与它同名的变量(包括对象、函数、类等)。

// 使用枚举类型进行操作
enum People {
  student,
  teacher,
  clearer,
}
let People = {   // 报错
  name: "学生",
  age: 18,
  gender: "男",
};

三.基础枚举类型

1. 数字枚举

数字枚举会自动为成员赋值,从 0 开始递增,也可手动设置初始值。

自动递增

enum People {  // 自动从0开始递增
  student, // 0
  teacher, // 1
  clearer, // 2
}

设置递增的开始值

enum People {
  student = 10, // 10
  teacher, // 11
  clearer, // 12
}

手动设置数值

enum People {
  student = 10,
  teacher = 23,
  clearer = 234,
}

2. 字符串枚举

字符串枚举的每个成员都得手动赋值为字符串或者其他字符串枚举成员。

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

// 使用字符串枚举
const dir: Direction = Direction.Up;
console.log(dir); // 输出: UP

3. 异构枚举

异构枚举是指枚举中同时包含数字和字符串成员。不过在实际开发中,这种枚举使用得较少,因为容易使代码逻辑变得复杂。

enum Result {
  Success = 'OK',
  Failure = 0
}

4.常量枚举

let  和 var 都是不允许的声明只能使用const

常量枚举通过 const enum 来定义,它和普通枚举的最大区别在于,常量枚举会在编译阶段被移除,直接把值内联到使用的地方,这样能减少编译后代码的体积。

const 声明的枚举会被编译成常量

普通声明的枚举编译完后是个对象

编译前得代码:

enum People {
  student = 10,
  teacher = 23,
  clearer = 234,
}

const enum animal {
  dog,
  cat,
  pig,
}

console.log(People.student);
console.log(animal.dog);

编译后的JavaScript代码:

var People;
(function (People) {
    People[People["student"] = 10] = "student";
    People[People["teacher"] = 23] = "teacher";
    People[People["clearer"] = 234] = "clearer";
})(People || (People = {}));
console.log(People.student);
console.log(0 /* animal.dog */);

四.枚举的特点

1.同名 Enum 的合并

多个同名的 Enum 结构会自动合并。

enum Color {
  Red,
  Green,
}

enum Color {
  black = 2,
}

enum Color {
  blue = 4,
  yellow = 6,
}

// 上面相当于就是下面得:
const Color = {
  Red: 0,
  Green: 1,
  black: 2,
  blue: 4,
  yellow: 6,
};

上面示例中,系统会自动把它们合并。

为什么可以合并,且看编译为JavaScript的代码就明白了:

var Color;
(function (Color) {
    Color[Color["Red"] = 0] = "Red";
    Color[Color["Green"] = 1] = "Green";
})(Color || (Color = {}));
(function (Color) {
    Color[Color["black"] = 2] = "black";
})(Color || (Color = {}));
(function (Color) {
    Color[Color["blue"] = 4] = "blue";
    Color[Color["yellow"] = 6] = "yellow";
})(Color || (Color = {}));

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

enum Color {
  Red,
  Green,
}
enum Color {
  black,
}
enum Color {
  blue,
  yellow = 6,
}

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

enum Color {
  Red,
  Green,
}
enum Color {
  black = 34,
}
enum Color {
  blue = 4,
  yellow = 6,
  Green = 255, // 报错,不能重复
}

同名 Enum 合并的另一个限制是,所有定义必须同为 const 枚举或者非 const 枚举,不允许混合使用。

2.反向映射

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

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

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

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

且看编译后的JavaScript代码部分

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 = {}));
console.log(Weekdays[3]); // Wednesday

就比如这个代码:

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

上面代码有两个赋值运算符(=),实际上等同于下面的代码。

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

注意,对于字符串枚举,不存在反向映射

enum Color {
  Red = "app",
  Green = "ppp",
  Blue = "www",
}

编译后的JavaScript代码:

var Color;
(function (Color) {
    Color["Red"] = "app";
    Color["Green"] = "ppp";
    Color["Blue"] = "www";
})(Color || (Color = {}));

可以发现:字符串枚举编译后只有一组赋值。

五.总结

  1. 数字枚举:能自动赋值,也能手动设置初始值,支持反向映射。
  2. 字符串枚举:所有成员都必须是字符串,不支持反向映射,提高了代码的可读性。
  3. 异构枚举:同时包含数字和字符串成员,实际开发中较少使用。
  4. 常量枚举:编译阶段会被移除,直接内联值,可减少代码体积。
  5. 同名枚举合并:同名枚举可以合并,整合成员。
  6. 反向映射:数字枚举特有的特性,支持值到名称的映射。

下一篇:TypeScript---type类型

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐