Typescript - enum 枚举类型(数值型枚举 / 字符串枚举 / 常量枚举 / 异构枚举 / 计算枚举成员 / 联合枚举和枚举成员类型 / 运行时的枚举 / 环境枚举 / 对象与枚举)教程
前言
Enums(枚举)是 TypeScript 的少数功能之一,它不是 JavaScript 的类型级扩展,仅支持数字的和基于字符串的枚举。
使用枚举您可以定义一组带名字的常量,并且清晰地表达意图或创建一组有区别的用例。
通俗介绍
其实还有很多例子,比如后端日常返回 0 / 1 等状态时,我们都可以使用枚举去定义,这样可以提高代码的可读性,便于后续的维护。
通俗来说,枚举就是一个对象的所有可能取值的集合, 在日常生活中也很常见,例如表示星期的 SUNDAY、MONDAY、TUESDAY、WEDNESDAY、THURSDAY、FRIDAY、SATURDAY 就可以看成是一个枚举。
您看,一个星期有 7 天(是固定的),那么你就可以把它 “枚举” 出来,供你程序使用。
再比如,后端返回的字段使用 0 - 6 标记对应的日期,这时候就可以使用枚举可提高代码可读性。
如果您还不懂的话也没关系,看了后面的示例,最后再回过头来看这里!
数值型枚举
枚举类型的值是数字类型,因此它们被称为数字类型枚举,成员的值可以不用初始化,因为具有自增行为。
首先从数字枚举开始,一个枚举可以用 enum 关键字来定义。
enum Direction {Up = 1, Down, Left, Right,
}
上面,我们有一个数字枚举,其中 Up 被初始化为 1 ,所有下面的成员从这一点开始自动递增。
换句话说,Direction.Up 的值是 1 ,Down 是 2,Left 是 3,Right 是 4。
如果您愿意,可以完全不使用初始化器:
enum Direction {Up,Down,Left,Right,
}
这里,Up 的值是 0,Down 是 1,依次类推。
这种 自动递增 的行为对于我们可能不关心成员值本身,但关心每个值与同一枚举中的其他值不同的情况很有用。
使用枚举很简单,您只需将任何成员作为 枚举本身的一个属性来访问,并使用枚举的名称来声明类型:
enum UserResponse {No = 0,Yes = 1,
}function respond(recipient: string, message: UserResponse): void {// ...
}respond("Princess Caroline", UserResponse.Yes);
数字枚举可以混合在计算和常量成员中(见下文)。简而言之,没有初始化器的枚举要么需要放在第一位,要么必须放在用数字常量或其他常量枚举成员初始化的数字枚举之后。
您看,下面的情况就是不允许的:
enum E {A = getSomeValue(), B, // Ⓧ Enum成员必须有初始化器。
}
字符串枚举
在一个字符串枚举中,每个成员都必须用一个字符串字头或另一个字符串枚举成员进行常量初始化。
字符串枚举是一个类似的概念,但有一些细微的运行时差异。
enum Direction {Up = "UP", Down = "DOWN", Left = "LEFT", Right = "RIGHT",
}
虽然字符串枚举没有自动递增的行为,但字符串枚举有一个好处,那就是它们可以很好地 “序列化”。
换句话说,如果你在调试时不得不读取一个数字枚举的运行时值,这个值往往是不透明的,它本身并不传达任何有用的意义(尽管 反向映射 能帮你),字符串枚举允许你在代码运行时给出一个有意义的、可读的值,与枚举成员本身的名称无关。
常量枚举
常量枚举会带来一个对性能的提升。
常量枚举通过在枚举上使用 const 修饰符来定义,常量枚举不同于常规的枚举,他们会在编译阶段被删除。
const enum Size {WIDTH = 10,HEIGHT = 20
}const area = Size.WIDTH * Size.HEIGHT; // 200
常量枚举成员在使用的地方会被内联进来,之所以可以这么做是因为,常量枚举不允许包含计算成员。
如上代码所示,在运行时是没有 Size 变量的,所以常量枚举会带来一个对性能的提升。
异构枚举
从技术上讲,枚举可以与字符串和数字成员混合。
枚举可以混合字符串和数字成员,但一般没必要这么做。
enum Person {name = 1,age = 2,love = 'LOVE',hobby = 'HOBBY'
}console.log(Person.name); // 1
console.log(Person.hobby); // HOBBY
计算枚举成员
您可以通过任意表达式设置枚举成员的值。
enum NoYesNum {No = 123,Yes = Math.random(), // OK
}
这是一个数字枚举。字符串枚举和异构枚举会有更多的限制。
例如,我们不能调用某些方法来设定枚举成员的值:
enum NoYesStr {No = 'No',//@ts-ignore: Computed values are not permitted in// an enum with string valued members.Yes = ['Y', 'e', 's'].join(''),
}
联合枚举和枚举成员类型
有一个特殊的常量枚举成员的子集没有被计算:字面枚举成员。
字面枚举成员是一个没有初始化值的常量枚举成员,或者其值被初始化为:
- 任何字符串(例如:“foo”, “bar”, “baz”)。
- 任何数字字头(例如:1,100)
- 应用于任何数字字面的单数减号(例如:-1,-100)
如下代码所示:
enum ShapeKind {Circle,Square,
}
interface Circle {kind: ShapeKind.Circle;radius: number;
}
interface Square {kind: ShapeKind.Square;sideLength: number;
}
let c: Circle = {kind: ShapeKind.Square, // Ⓧ 类型 'ShapeKind.Square' 不能被分配给类型 'ShapeKind.Circle'radius: 100,
};
另一个变化是枚举类型本身有效地成为每个枚举成员的联盟。
通过联合枚举,类型系统能够利用这一事实,即它知道存在于枚举本身的精确的值集。
正因为如此,TypeScript 可以捕捉到我们可能错误地比较数值的错误。比如说:
enum E {Foo,Bar,
}function f(x: E) {if (x !== E.Foo || x !== E.Bar) {// Ⓧ 这个条件将总是返回'true',因为'E.Foo'和'E.Bar'的类型没有重合。//...}
}
在这个例子中,首先检查了 x 是否是 E.Foo。
如果这个检查成功了,那么我们的 || 就会短路,if 的主体就会运行。
然而,如果检查没有成功,那么 x 就只能是 E.Foo,所以看它是否等于 E.Bar 就没有意义了。
运行时的枚举
枚举是在运行时存在的真实对象。
例如,请看下面这个枚举:
enum E {X,Y,Z,
}
实际上可以被传递给函数:
enum E {X,Y,Z,
}function f(obj: { X: number }) {return obj.X;
}// 可以正常工作,因为'E'有一个名为'X'的属性,是一个数字。
f(E);
编译时的枚举
尽管 Enum 是在运行时存在的真实对象,keyof 关键字的工作方式与你对典型对象的预期不同。
相反,使用 keyof typeof 来获得一个将所有 Enum 键表示为字符串的类型。
enum LogLevel {ERROR,WARN,INFO,DEBUG,
}
/** * 这相当于: * type LogLevelStrings = 'ERROR' | 'WARN' | 'INFO' | 'DEBUG'; */
type LogLevelStrings = keyof typeof LogLevel;function printImportant(key: LogLevelStrings, message: string) {const num = LogLevel[key];if (num <= LogLevel.WARN) {console.log("Log level key is:", key);console.log("Log level value is:", num);console.log("Log level message is:", message);}
}
printImportant("ERROR", "This is a message");
反向映射
除了为成员创建一个带有属性名称的对象外,数字枚举的成员还可以得到从枚举值到枚举名称的反向映射。
例如,在这个例子中:
enum Enum {A,
}
let a = Enum.A;
let nameOfA = Enum[a]; // "A"
TypeScript 将其编译为以下的 JavaScript:
"use strict";
var Enum;
(function (Enum) {Enum[Enum["A"] = 0] = "A";
})(Enum || (Enum = {}));
let a = Enum.A;
let nameOfA = Enum[a]; // "A"
在这段生成的代码中,一个枚举被编译成一个对象,它同时存储了正向 (name -> value) 和反向 (value -> name) 的映射关系。
对其他枚举成员的引用总是以属性访问的方式发出,而且从不内联。
环境枚举
环境枚举是用来描述已经存在的枚举类型的形状。
declare enum Enum {A = 1, B, C = 2,
}
环境枚举和非环境枚举之间的一个重要区别是,在常规枚举中,如果其前面的枚举成员被认为是常量,那么没有初始化器的成员将被认为是常量。
相反,一个没有初始化器的环境(和非常量)枚举成员总是被认为是计算的。
对象与枚举
在现代 TypeScript 中,你可能不需要一个枚举,因为一个对象的常量就足够了:
const enum EDirection {Up,Down,Left,Right,
}const ODirection = {Up: 0,Down: 1,Left: 2,Right: 3,
} as const;// (enum member) EDirection.Up = 0
EDirection.Up;// (property) Up: 0
ODirection.Up;// 将枚举作为一个参数
function walk(dir: EDirection) {}// 它需要一个额外的行来拉出数值
type Direction = typeof ODirection[keyof typeof ODirection];
function run(dir: Direction) {}walk(EDirection.Left);
run(ODirection.Right);
普通对象与 TypeScript 的枚举相比,支持这种格式的最大理由就是,
它使你的代码库与 JavaScript 的状态保持一致,when/if 枚举被添加到 JavaScript 中,那么你可以转移到额外的语法。
写在后面
关于 TS enum 枚举类型,本文只是入门教程,并非 “深度” 分析。
Typescript - enum 枚举类型(数值型枚举 / 字符串枚举 / 常量枚举 / 异构枚举 / 计算枚举成员 / 联合枚举和枚举成员类型 / 运行时的枚举 / 环境枚举 / 对象与枚举)教程相关推荐
- 02.Python基础_标准数据类型_数值型_字符串
文章目录 1.标准数据类型 1.1 数据类型 1.1.1 整数型int 1.1.2 浮点型float 1.2 数字类型的转换 1.2.1浮点转整数型 1.2.2 整数型转化为浮点型 1.2.3 数值型 ...
- Mysql列类型-数值型
2019独角兽企业重金招聘Python工程师标准>>> 一.整数型: 1.取值范围: tinyint smallint mediumint int bigin ...
- sql server中的怎么把数值型转换为字符串
①select cast(字段 as varchar) from 表名 ②select convert(varchar(50),字段) from 表名
- 前端:JS/17/前篇总结(JS程序的基本语法,变量),数据类型-变量的类型(数值型,字符型,布尔型,未定义型,空型),数据类型转换,typeof()判断数据类型,从字符串提取整数或浮点数的函数
JS程序的基本语法 1,JS是区分大小写的,如:Name和name是不同的: 2,JS中每一条语句,一般以英文的分号(;)结束,在Java中是严格地一定要加上分号,不然会报错:但在JavaScript ...
- mysql 空位补0_MySQL-13(表的创建、数值类型整型、float/decimal、ZEROFILL、BIT(M))
# 1. 表的创建 基本语法: CREATE TABLE table_name( column1 datatype, column2 datatype, column3 datatype )ch ...
- mysql 数值型注入_slq-注入总结(中)
上一节中,大致把sql中的函数记录了下,如果有什么不足希望各位师傅斧正.晚自习没课,所以现在把常见的注入方式,以及利用过程讲一下. 注入类型 数值型注入 也就是说后台的sql语句直接拼接的一个数值,可 ...
- Java中的基本数据类型讲解(数值型、字符型、布尔型)
数据类型 数据类型的分类 分为 基本数据类型和引用数据类型 基本数据类型 基本数据类型分为数值型.字符型和布尔类型 数值型 数值型分为整数型和浮点型(小数型) 整数型 包含:int. short. b ...
- java整形变量转换字符串_JAVA整型转换字符串以及相互转换的相关实例
JAVA整型转换字符串以及相互转换的相关实例.java数据类型之间的转换.怎么把整数 int 转换成字串 String ?怎么把字符串 String 转换成整数 int类型? 整型与字符串转换实例: ...
- [JVM]了断局:常量池 VS 运行时常量池 VS 字符串常量池
一.前言 最近在看JVM, 常量池, 运行时常量池,字符串常量池 这个看的有点懵. 整理一下. class常量池 是在编译的时候每个class都有的. 在编译阶段,存放的是常量的 符号引用 . ...
- class常量池、运行时常量池 和 字符串常量池 的区别
文章目录 一.概念 1.class常量池(Constant Pool) 1.1.字面量 1.2.符号引用 2.Runtime Constant Pool( 运行时常量池 ) 3.String Pool ...
最新文章
- centos7 设置中文
- php读取pdf文件
- 保持边缘平滑的图像(曲率)
- arduinowifi.send怎么获取响应_ChatterBot代码解读-获取对话
- 上帝就在机器里:复杂算法背后隐藏的可怕现实
- [FFmpeg] ffplay 播放灰度帧
- Android studio 4.0 Layout Inspector查看当前Activity
- Linux桌面鼠标取词自动翻译
- 批处理bat下载FTP服务器上某个目录下的文件
- web前端开发工程师的真实能力如何判定?大厂资深前端指点迷津
- 2022年PC推荐-组装机及品牌机 2022年8月16日(持续更新)
- 计算机二级Python第二弹课后题来袭!冲冲冲!!!
- python爬取餐饮数据_使用 Python 分析全国所有必胜客餐厅
- [转] Phun,让人惊讶的小程序
- 求助:hmailserver+roundcube启用密码插件后,用户无法修改密码问题
- ArcGIS 缓冲区与叠加分析
- 常用运行命令win10
- php花朵飘落特效,【新年气象】WordPress 主题添加花瓣飘落特效
- 8万条数据告诉你:跟着大股东和高管买他家股票,能赚钱吗?【邢不行|量化小讲堂系列60-实战篇】
- android开机字库加载过程,小米手机字库维修更换和EMMC字库编程烧写方法教程