TypeScript(七)枚举

151 阅读3分钟

枚举

enum 类型是对 JavaScript 标准数据类型的一个补充(使用枚举类型可以为一组数值赋予友好的名字),枚举类型用于定义数值集合。

enum 成员

下面示例声明了一个 Enum 结构 Color,里面包含三个成员 RedGreenBlue。第一个成员的值默认为整数 0,第二个为 1,第三个为 2,以此类推。

enum Color {
  Red,
  Green,
  Blue,
}

let c: Color = Color.Green;
console.log(c); // Output: 1

可以手动的指定成员的数值,指定成员数值后的值依次递增。

enum Color {
  Red,
  Green = 5,
  Blue,
  Yellow,
  Black,
  White,
}

const c = Color.Red;
const c1 = Color.Blue;

console.log(c, c1); // Output: 0 6

如果手动指定的成员的值比它本身的索引小,那么就会出现和之前成员值相等的情况,下面Color类型的 GreenBlue 成员就出现了值相同的情况, 因为Green本身值为 1 ,而我们手动指定了 Blue 成员的值为 1,所以它们的值相同。

enum Color {
  Red,
  Green,
  Blue = 1,
  Yellow,
  Black,
  White,
}

const c = Color.Green;
const c1 = Color.Yellow;

console.log(c, c1); // Output: 1 2
console.log(Color.Green === Color.Blue); // Output true

可以为 enum 成员赋值任意数值,但不能是 bigintboolean

enum Mix {
  Num = 1000,
  Binary = 0x11111,
  BinaryOperation = 4 >> 1,
  UserName = "rinvay",
  Flag = true, // error Type 'boolean' is not assignable to type 'number' as required for computed enum member values.
  BigInt = 7n, // error Type 'bigint' is not assignable to type 'number' as required for computed enum member values.
}

同名 enum

同名的 enum 结构会自动合并。

enum Word {
  A,
  B,
}

enum Word {
  C = 2,
  D = 3,
}

console.log(Word.A, Word.B, Word.C, Word.D); // Output: 0 1 2 3

同名的 enum 内部成员不能重复,哪怕成员的数值是相同的,下面两个 Word 类型都存在成员 B ,就会报错。

enum Word {
  A,
  B,
}

enum Word {
  B = 1, // error 标识符“B”重复。
  C = 3,
}

console.log(Word.A, Word.B, Word.C);

在多个同名的 enum 枚举中,只有一个声明可以省略其第一个枚举元素的初始化表达式。

enum Word {
  A,
  B,
}

enum Word {
  C, // error 在包含多个声明的枚举中,只有一个声明可以省略其第一个枚举元素的初始化表达式。
  D,
}

enum Word {
  A,
  B,
}

enum Word {
  C = 0, // ok
  D,
}

enum 编译

enum 它既是一种类型,也是一个值。因为绝大多数 TypeScript 语法都是类型语法,编译后会全部去除,最终都会以 Js 语法呈现, enum 编译后会变成 JavaScript 对象,留在代码中。

enum Word {
  A,
  B,
  C,
  D,
}

上面的 TypeScript 代码最终会编译成下面的一个 JavaScript 对象,可以看到对象中不只有 A, B, C, D 属性。还有 0, 1, 2, 3 可以通过 Word[x] 取到 A, B, C, D 的值。

var Word;
(function (Word) {
  Word[(Word["A"] = 0)] = "A";
  Word[(Word["B"] = 1)] = "B";
  Word[(Word["C"] = 2)] = "C";
  Word[(Word["D"] = 3)] = "D";
})(Word || (Word = {}));

console.log(Word); // {0: 'A', 1: 'B', 2: 'C', 3: 'D', A: 0, B: 1, C: 2, D: 3}

enum 成员赋值字符串的时候 TypeScript 处理会有一些区别。

enum Word {
  A,
  B = 4 >> 1,
  C = "2",
  D = "rinvay",
}

编译后的 Word 对象中,成员赋值字符串的时候并不会生成以字符串为 key 的健值对。所以上面的 Word 类型并不能通过 Word['rinvay'] 取到值 D

var Word;
(function (Word) {
  Word[(Word["A"] = 0)] = "A";
  Word[(Word["B"] = 2)] = "B";
  Word["C"] = "2";
  Word["D"] = "rinvay";
})(Word || (Word = {}));

console.log(Word); // {0: 'A', 2: 'B', A: 0, B: 2, C: '2', D: 'rinvay'}

keyof 运算符

keyof 运算符可以取出 enum 类型的所有成员名作为联合类型返回。

enum Bool {
  No,
  Yes,
}

type Flag = keyof typeof Bool;

const no: Flag = "No";
const yes: Flag = "Yes";

如果要返回 enum 所有的成员值,可以使用 in 运算符。

enum Bool {
  No = "no",
  Yes = "yes",
}

/**
 * 等同
 * type Flag = {
 *   no: string;
 *   yes: string;
 * };
 */
type Flag = { [key in Bool]: string };

const flag: Flag = {
  no: "0",
  yes: "1",
};