一、概念
使用枚举我们可以定义一些带名字的常量。
我理解的是使用枚举,可以解决我们在项目中定义常量不规范的问题。
-
数字枚举
// 使用初始化器 enum Direction { // 定义数字枚举 Up = 1, // 使用初始化器,初始值1 Down, // 2 Left, // 3 Right // 4 // ...定义依次递增 } // 不使用初始化器 enum Direction { Up, // 0 Down, // 1 Left, Right, }
通过枚举的属性来访问枚举成员,和枚举的名字来访问枚举类型
enum Response { No = 0, Yes = 1, } function respond(recipient: string, message: Response): void { console.log(recipient + ' ' + message); } respond("Princess Caroline", Response.Yes) // Princess Caroline 1 respond("Princess Caroline", 1000) // Princess Caroline 1000 这里值没有在Response里定义也不报错 respond("Princess Caroline", 'df') // error 类型“"df"”的参数不能赋给类型“Response”的参数。ts(2345)
数字枚举中使用函数计算得出的常量成员,后面紧跟着的常量成员必须使用常量进行初始化。
function getSomeValue(): number { return 123 } enum E { A = getSomeValue(), B = 1, // error! 前面的'A'不是常量初始化的,所以'B'需要一个初始化器 C // 2 no error }
-
字符串枚举
在一个字符串枚举里,每个成员都必须用字符串字面量,或另外一个字符串枚举成员进行初始化。
enum Direction { Up = "UP", Down = "DOWN", Left = "LEFT", Right = "RIGHT", }
-
异构枚举
enum BooleanLikeHeterogeneousEnum { // 不建议这样使用 No = 0, Yes = "YES", }
-
计算的成员和常量成员
-
它是枚举的第一个成员且没有初始化器,这种情况下它被赋予值 0
// E.X is constant: enum E { X // 0 }
-
它不带有初始化器且它之前的枚举成员是一个 数字常量。 这种情况下,当前枚举成员的值为它上一个枚举成员的值加1。
enum E2 { A = 1, B, // 2 C // 3 }
-
枚举成员使用 常量枚举表达式初始化。
使用规则:
一个枚举表达式字面量(主要是字符串字面量或数字字面量)
一个对之前定义的常量枚举成员的引用(可以是在不同的枚举类型中定义的)
带括号的常量枚举表达式
一元运算符 +, -, ~其中之一应用在了常量枚举表达式
常量枚举表达式做为二元运算符 +, -, *, /, %, <<, >>, >>>, &, |, ^的操作对象
若常数枚举表达式求值后为 NaN或 Infinity,则会在编译阶段报错。enum FileAccess { // constant members None, Read = 1 << 1, Write = 1 << 2, ReadWrite = Read | Write, // computed member G = "123".length }
-
枚举成员成为类型
enum ShapeKind { Circle, Square, } interface Circle { kind: ShapeKind.Circle; radius: number; } interface Square { kind: ShapeKind.Square; sideLength: number; } let c: Circle = { kind: ShapeKind.Square, // Error! // kind: 1, no error // kind: 123, no error // kind: 'str', // 不能将类型“string”分配给类型“ShapeKind.Circle”。 radius: 100, }
短路问题
enum E { Foo, Bar } function f(x: E) { if (x !== E.Foo || x !== E.Bar) { // 判断无意义,总是会通过第一个判断 // ~~~~~~~~~~~ // Error! Operator '!==' cannot be applied to types 'E.Foo' and 'E.Bar'. console.log(x); } }
-
将枚举当作参数传入函数中
枚举对象
enum E { X, Y, Z } function f(obj: { X: number }) { return obj.X; // Works, since 'E' has a property named 'X' which is a number. } console.log(f(E)); // 0
反向映射:从枚举值到枚举名字。
enum Enum { A } let a = Enum.A; let nameOfA = Enum[a]; // "A"
生成的代码中,枚举类型被编译成一个对象,它包含了正向映射( name -> value)和反向映射( value -> name)。 引用枚举成员总会生成为对属性访问并且永远也不会内联代码。
要注意的是 不会为字符串枚举成员生成反向映射。
-
const枚举
减少重复代码定义产生的代码量开销
避免非直接的对枚举成员的访问const enum Enum { A = 1, B = A * 2 }
常量枚举只能使用常量枚举表达式,并且不同于常规的枚举,它们在编译阶段会被删除。
常量枚举成员在使用的地方会被内联进来。
常量枚举不允许包含计算成员。// 使用常量枚举 const enum Directions { Up, Down, Left, Right } let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right] // [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */] // 使用计算初始化枚举成员 function getval() { return 123 } enum Directions { Up = getval(), Down = 1 } let directions = [Directions.Up, Directions.Down] // [123, 1]
-
外部枚举
外部枚举用来描述已经存在的枚举类型的形状。
declare enum Enum { // 没有完全弄懂这个declare,据网上博文描述, A = 1, B, C = 2 }
外部枚举和非外部枚举之间有一个重要的区别,在正常的枚举里,没有初始化方法的成员被当成常数成员。 对于非常数的外部枚举而言,没有初始化方法时被当做需要经过计算的。