共计 5084 个字符,预计需要花费 13 分钟才能阅读完成。
导读 | 这篇文章主要介绍了 TypeScript 枚举类型,TypeScript 在 ES 原有类型基础上加入枚举类型,使得在 TypeScript 中也可以给一组数值赋予名字,这样对开发者比较友好,可以理解枚举就是一个字典,文章内容围绕 TypeScript 枚举类型展开内容, 需要的朋友可以参考一下 |
TypeScript 在 ES 原有类型基础上加入枚举类型,使得在 TypeScript 中也可以给一组数值赋予名字,这样对开发者比较友好,可以理解枚举就是一个字典。
枚举类型使用 enum 来定义:
enum Day {
SUNDAY,
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY
}
上面定义的枚举类型的 Day,它有 7 个值,TypeScript 会为它们每个值分配编号,默认从 0 开始,在使用时,就可以使用名字而不需要记数字和名称的对应关系了:
enum Day {
SUNDAY = 0,
MONDAY = 1,
TUESDAY = 2,
WEDNESDAY = 3,
THURSDAY = 4,
FRIDAY = 5,
SATURDAY = 6
}
下面是将上面代码转译为 JavaScript 后的效果:
var Day = void 0;
(function (Day) {Day[Day["SUNDAY"] = 0] = "SUNDAY";
Day[Day["MONDAY"] = 1] = "MONDAY";
Day[Day["TUESDAY"] = 2] = "TUESDAY";
Day[Day["WEDNESDAY"] = 3] = "WEDNESDAY";
Day[Day["THURSDAY"] = 4] = "THURSDAY";
Day[Day["FRIDAY"] = 5] = "FRIDAY";
Day[Day["SATURDAY"] = 6] = "SATURDAY";
})(Day || (Day = {}));
可以看到,每一个值都被赋予了对应的数字。
在 TypeScript 中,我们需要通过点的形式获取枚举集合中的成员:
console.log(Day.SUNDAY) // 0
console.log(Day.MONDAY) // 1
说完枚举类型的基本使用,下面就来看一下常见的枚举类型。
在上面的例子中,在仅指定常量命名的情况下,定义的就是一个默认从 0 开始递增的数字集合,称之为数字枚举。如果想要从其他值开始递增,可以将第一个值的索引值进行指定:
enum Color {
Red = 2,
Blue,
Yellow
}
console.log(Color.Red, Color.Blue, Color.Yellow); // 2 3 4
可以对一个字段指定一个索引值,那他后面没有指定索引值的就会依次加一:
// 指定部分字段,其他使用默认递增索引
enum Status {
Ok = 200,
Created,
Accepted,
BadRequest = 400,
Unauthorized
}
console.log(Status.Created, Status.Accepted, Status.Unauthorized); // 201 202 401
除此之外,还可以给每个字段指定不连续的任意索引值:
enum Status {
Success = 200,
NotFound = 404,
Error = 500
}
console.log(Status.Success, Status.NotFound, Status.Error); // 200 404 500
数字枚举在定义值时,可以使用计算值和常量。但是要注意,如果某个字段使用了计算值或常量,那么该字段后面紧接着的字段必须设置初始值,这里不能使用默认的递增值了,来看例子:
// 初值为计算值
const getValue = () => {return 0;};
enum ErrorIndex {a = getValue(),
b, // error 枚举成员必须具有初始化的值
c
}
enum RightIndex {a = getValue(),
b = 1,
c
}
// 初值为常量
const Start = 1;
enum Index {
a = Start,
b, // error 枚举成员必须具有初始化的值
c
}
TypeScript 将定义值是字符串字面量的枚举称为字符串枚举,字符串枚举值要求每个字段的值都必须是字符串字面量,或者是该枚举值中另一个字符串枚举成员:
// 使用字符串字面量
enum Message {
Error = "Sorry, error",
Success = "Hoho, success"
}
console.log(Message.Error); // 'Sorry, error'
// 使用枚举值中其他枚举成员
enum Message {
Error = "error message",
ServerError = Error,
ClientError = Error
}
console.log(Message.Error); // 'error message'
console.log(Message.ServerError); // 'error message'
注意:这里的其他枚举成员指的是同一个枚举值中的枚举成员,因为字符串枚举不能使用常量或者计算值,所以不能使用其他枚举值中的成员。
定义枚举类型的值时,可以通过 Enum[‘key’] 或者 Enum.key 的形式获取到对应的值 value。TypeScript 还支持反向映射,但是反向映射只支持数字枚举,不支持字符串枚举。
来看下面的例子:
enum Status {
Success = 200,
NotFound = 404,
Error = 500
}
console.log(Status["Success"]); // 200
console.log(Status[200]); // 'Success'
console.log(Status[Status["Success"]]); // 'Success'
TypeScript 中定义的枚举,编译之后其实是一个对象,生成的代码中,枚举类型被编译成一个对象,它包含了正向映射(name -> value)和反向映射(value -> name)。
下面来看看上面代码中的 Status 编译后的效果:
{
200: "Success",
404: "NotFound",
500: "Error",
Error: 500,
NotFound: 404,
Success: 200
}
可以看到,TypeScript 会把定义的枚举值的字段名分别作为对象的属性名和属性值,把枚举值的字段值分别作为对象的属性值和属性名,同时添加到对象中。这样既可以通过枚举值的字段名得到值,也可以通过枚举值的值得到字段名。
异构枚举就是枚举值中成员值既有数字类型又有字符串类型,如下:
enum Result {
Faild = 0,
Success = "Success"
}
在开发过程中不建议使用异步枚举。因为往往将一类值整理为一个枚举值时,它们的特点是相似的。比如在做接口请求时的返回状态码,如果是状态码都是数值,如果是提示信息,都是字符串,所以在使用枚举的时候,往往是可以避免使用异构枚举的,主要是做好类型的整理。
在 TypeScript 中,定义了枚举值之后,编译成 JavaScript 的代码会创建一个对应的对象,这个对象可以在程序运行时使用。但是如果使用枚举只是为了让程序可读性好,并不需要编译后的对象呢?这样会增加一些编译后的代码量。TypeScript 中有一个 const enum(常量枚举),在定义枚举的语句之前加上 const 关键字,这样编译后的代码不会创建这个对象,只是会从枚举里拿到相应的值进行替换:
enum Status {
Off,
On
}
const enum Animal {
Dog,
Cat
}
const status = Status.On;
const animal = Animal.Dog;
上面的代码编译成 JavaScript 之后是这样的:
var Status;
(function(Status) {Status[(Status["Off"] = 0)] = "Off";
Status[(Status["On"] = 1)] = "On";
})(Status || (Status = {}));
var status = Status.On;
var animal = 0; // Dog
对于 Status 的处理,先是定义一个变量 Status,然后定义一个立即执行函数,在函数内给 Status 添加对应属性,首先 Status[“Off”] = 0 是给 Status 对象设置 Off 属性,并且值设为 0,这个赋值表达式的返回值是等号右边的值,也就是 0,所以 Status[Status[“Off”] = 0] = “Off” 相当于 Status[0] =“Off”。创建了这个对象之后,将 Status 的 On 属性值赋值给 status;再来看下 animal 的处理,编译后的代码并没有像 Status 创建一个 Animal 对象,而是直接把 Animal.Dog 的值 0 替换到了 const animal = Animal.Dog 表达式的 Animal.Dog 位置。
通过定义常量枚举,可以以清晰、结构化的形式维护相关联的常量集合。而且因为转译后抹除了定义、内联成员值,所以在代码的体积和性能方面并不会比直接内联常量值差。
如果枚举值里所有成员都是字面量类型的值,那么枚举的每个成员和枚举值本身都可以作为类型来使用,我们称这样的枚举成员为字面量枚举成员。
满足条件的枚举成员的值有以下三种:
没有初始值的枚举成员,例如:enum E {A}
值为字符串字面量,例如:enum E {A = ‘a’}
值为数值字面量,或者带有 - 符号的数值字面量,例如:enum E {A = 1}、enum E {A = -1}
当所有枚举成员都拥有字面量枚举值时,就枚举成员成为了类型:
enum Animal {
Dog = 1,
Cat = 2
}
interface Dog {type: Animal.Dog;}
interface Cat {type: Animal.Cat;}
let cat: Cat = {type: Animal.Dog // error [ts] 不能将类型“Animal.Dog”分配给类型“Animal.Cat”};
let dog: Dog = {type: Animal.Dog};
可以看到,代码的第七行使用 Animal.Dog 作为类型,指定接口 Dog 的必须有一个 type 字段,且类型为 Animal.Dog。
当枚举值符合条件时,这个枚举值就可以看做是一个包含所有成员的联合类型:
enum Status {
Off,
On
}
interface Light {status: Status;}
enum Animal {
Dog = 1,
Cat = 2
}
const light1: Light = {status: Animal.Dog // error 不能将类型“Animal.Dog”分配给类型“Status”};
const light2: Light = {status: Status.Off};
const light3: Light = {status: Status.On};
上面例子定义接口 Light 的 status 字段的类型为枚举值 Status,那么此时 status 的属性值必须为 Status.Off 和 Status.On 中的一个,也就是相当于 status: Status.Off | Status.On。
说完常见的枚举类型,最后来看看枚举合并的概念。对于枚举类型的值,我们可以分开进行声明:
enum Day {
SUNDAY,
MONDAY,
TUESDAY
}
enum Day {
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY
}
这时 TypeScript 就会对这个枚举值进行合并操作,合并后编译为 JavaScript 的代码如下:
var Day = void 0;
(function (Day) {Day[Day["SUNDAY"] = 0] = "SUNDAY";
Day[Day["MONDAY"] = 1] = "MONDAY";
Day[Day["TUESDAY"] = 2] = "TUESDAY";
Day[Day["WEDNESDAY"] = 3] = "WEDNESDAY";
Day[Day["THURSDAY"] = 4] = "THURSDAY";
Day[Day["FRIDAY"] = 5] = "FRIDAY";
Day[Day["SATURDAY"] = 6] = "SATURDAY";
})(Day || (Day = {}));
到此这篇关于详解 TypeScript 枚举类型的文章就介绍到这了