详解 TypeScript 枚举类型


Posted in Javascript onNovember 02, 2021

前言:

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

说完枚举类型的基本使用,下面就来看一下常见的枚举类型。

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
}

2. 字符串枚举

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'

注意:这里的其他枚举成员指的是同一个枚举值中的枚举成员,因为字符串枚举不能使用常量或者计算值,所以不能使用其他枚举值中的成员。

3. 反向映射

定义枚举类型的值时,可以通过 Enum['key'] 或者 Enum.key 的形式获取到对应的值 valueTypeScript 还支持反向映射,但是反向映射只支持数字枚举,不支持字符串枚举。

来看下面的例子:

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 会把定义的枚举值的字段名分别作为对象的属性名和属性值,把枚举值的字段值分别作为对象的属性值和属性名,同时添加到对象中。这样既可以通过枚举值的字段名得到值,也可以通过枚举值的值得到字段名。

4. 异构枚举

异构枚举就是枚举值中成员值既有数字类型又有字符串类型,如下:

enum Result {
  Faild = 0,
  Success = "Success"
}

在开发过程中不建议使用异步枚举。因为往往将一类值整理为一个枚举值时,它们的特点是相似的。比如在做接口请求时的返回状态码,如果是状态码都是数值,如果是提示信息,都是字符串,所以在使用枚举的时候,往往是可以避免使用异构枚举的,主要是做好类型的整理。

5. 常量枚举

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位置。

通过定义常量枚举,可以以清晰、结构化的形式维护相关联的常量集合。而且因为转译后抹除了定义、内联成员值,所以在代码的体积和性能方面并不会比直接内联常量值差。

6. 枚举成员类型和联合枚举类型

如果枚举值里所有成员都是字面量类型的值,那么枚举的每个成员和枚举值本身都可以作为类型来使用,我们称这样的枚举成员为字面量枚举成员。

满足条件的枚举成员的值有以下三种:

  • 没有初始值的枚举成员,例如:enum E { A }
  • 值为字符串字面量,例如:enum E { A = 'a' }
  • 值为数值字面量,或者带有-符号的数值字面量,例如:enum E { A = 1 }、enum E { A = -1 }

(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

(2)联合枚举类型

当枚举值符合条件时,这个枚举值就可以看做是一个包含所有成员的联合类型:

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

7. 枚举合并

说完常见的枚举类型,最后来看看枚举合并的概念。对于枚举类型的值,我们可以分开进行声明:

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 枚举类型的文章就介绍到这了,更多相关TypeScript 枚举类型内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
张孝祥JavaScript学习阶段性总结(2)--(X)HTML学习
Feb 03 Javascript
jquery解决客户端跨域访问问题
Jan 06 Javascript
JavaScript检测字符串中是否含有html标签实现方法
Jul 01 Javascript
js实现仿百度风云榜可重复多次调用的TAB切换选项卡效果
Aug 31 Javascript
js实现兼容性好的微软官网导航下拉菜单效果
Sep 07 Javascript
Ext JS动态加载JavaScript创建窗体的方法
Jun 23 Javascript
一种基于浏览器的自动小票机打印实现方案(js版)
Jul 26 Javascript
微信小程序 数据访问实例详解
Oct 08 Javascript
JS实现网页抢购功能(触发,终止脚本)
Nov 27 Javascript
Vue2.0实现组件数据的双向绑定问题
Mar 06 Javascript
详解Node.js读写中文内容文件操作
Oct 10 Javascript
JavaScript高级程序设计之变量与作用域
Nov 17 Javascript
前端JavaScript大管家 package.json
JavaScript 原型与原型链详情
javascript实现计算器功能详解流程
JS创建或填充任意长度数组的小技巧汇总
Oct 24 #Javascript
一文彻底理解js原生语法prototype,__proto__和constructor
Oct 24 #Javascript
javascript遍历对象的五种方式实例代码
Oct 24 #Javascript
低门槛开发iOS、Android、小程序应用的前端框架详解
Oct 16 #Javascript
You might like
PHP安装攻略:常见问题解答(二)
2006/10/09 PHP
Javascript YUI 读码日记之 YAHOO.util.Dom - Part.3
2008/03/22 Javascript
基于jquery用于查询操作的实现代码
2010/05/10 Javascript
javascript各浏览器中option元素的表现差异
2011/04/07 Javascript
js 将json字符串转换为json对象的方法解析
2013/11/13 Javascript
jquery ajax 简单范例(界面+后台)
2013/11/19 Javascript
在javascript中实现函数数组的方法
2013/12/25 Javascript
jQuery瀑布流插件Wookmark使用实例
2014/04/02 Javascript
javascript动画之模拟拖拽效果篇
2016/09/26 Javascript
js运算符的一些特殊用法
2018/07/29 Javascript
使用Angular material主题定义自己的组件库的配色体系
2019/09/04 Javascript
ES6 Promise对象概念及用法实例详解
2019/10/15 Javascript
Vue过滤器,生命周期函数和vue-resource简单介绍
2021/01/12 Vue.js
[02:41]DOTA2亚洲邀请赛小组赛第三日 赛事回顾
2015/02/01 DOTA
Python 匹配任意字符(包括换行符)的正则表达式写法
2009/10/29 Python
python正则表达式修复网站文章字体不统一的解决方法
2013/02/21 Python
Python socket网络编程TCP/IP服务器与客户端通信
2017/01/05 Python
基于python log取对数详解
2018/06/08 Python
python pandas消除空值和空格以及 Nan数据替换方法
2018/10/30 Python
Python 使用Numpy对矩阵进行转置的方法
2019/01/28 Python
Python检查图片是否损坏及图片类型是否正确过程详解
2019/09/30 Python
python selenium循环登陆网站的实现
2019/11/04 Python
python列表返回重复数据的下标
2020/02/10 Python
详解使用scrapy进行模拟登陆三种方式
2021/02/21 Python
Europcar澳大利亚官网:全球汽车租赁领域的领导者
2019/03/24 全球购物
美国家用和厨房电器销售网站:Appliances Connection
2020/01/24 全球购物
安全教育心得体会
2013/12/29 职场文书
给医务人员表扬信
2014/01/12 职场文书
好邻里事迹材料
2014/01/16 职场文书
涉密人员保密承诺书
2014/05/28 职场文书
森林病虫害防治方案
2014/06/02 职场文书
办公楼租房协议书范本
2014/11/25 职场文书
开票员岗位职责
2015/02/12 职场文书
工商局个人工作总结
2015/03/03 职场文书
Django migrate报错的解决方案
2021/05/20 Python
python百行代码实现汉服圈图片爬取
2021/11/23 Python