如何在 TypeScript 中使用Enum(枚举)
liuian 2025-05-03 15:16 36 浏览
在 TypeScript 中,枚举 或枚举类型是具有一组常量值的常量长度的数据结构。这些常量值中的每一个都称为枚举的成员。在设置只能是一定数量的可能值的属性或值时,枚举很有用。
一个常见的例子是一副扑克牌中单张牌的花色值。抽出的每张牌要么是梅花、方块、红心或黑桃;除了这四个之外,没有可能的花色值,并且这些可能的值不太可能改变。因此,枚举将是一种有效且清晰的方式来描述一张牌的可能花色。
尽管 TypeScript 的大多数功能都可用于在编译期间引发错误,但枚举也可用作可以保存代码常量的数据结构。
TypeScript 在编译器发出的最终代码中将枚举转换为 JavaScript 对象。正因为如此,我们可以使用枚举使代码库更具可读性,因为我们可以将多个常量值分组在同一个数据结构中,同时,也使代码比仅使用不同的 const 变量更具有类型安全性。
本教程将解释用于创建枚举类型的语法、TypeScript 编译器在后台创建的 JavaScript 代码、如何提取枚举对象类型,以及游戏开发中涉及位标志的枚举用例。
准备工作
要遵循本教程,我们将需要:
一个环境,我们可以在其中执行 TypeScript 程序以跟随示例。要在本地计算机上进行设置,我们将需要以下内容:
为了运行处理 TypeScript 相关包的开发环境,同时,安装了 Node 和 npm(或 yarn)。本教程使用 Node.js 版本 14.3.0 和 npm 版本 6.14.5 进行了测试。要在 macOS 或 Ubuntu 18.04 上安装,请按照如何在 macOS 上安装 Node.js 和创建本地开发环境或如何在 Ubuntu 18.04 上安装 Node.js 的使用 PPA 安装部分中的步骤进行操作。如果我们使用的是适用于 Linux 的 Windows 子系统 (WSL),这也适用。
此外,我们需要在机器上安装 TypeScript 编译器 (tsc)。为此,请参阅官方 TypeScript 网站。
如果我们不想在本地机器上创建 TypeScript 环境,我们可以使用官方的 TypeScript Playground 来跟随。
我们将需要足够的 JavaScript 知识,尤其是 ES6+ 语法,例如解构、剩余参数和导入/导出。
本教程将参考支持 TypeScript 并显示内联错误的文本编辑器的各个方面。这不是使用 TypeScript 所必需的,但确实可以更多地利用 TypeScript 功能。为了获得这些好处,我们可以使用像 Visual Studio Code 这样的文本编辑器,它完全支持开箱即用的 TypeScript。我们也可以在 TypeScript Playground 中尝试这些好处。
本教程中显示的所有示例都是使用 TypeScript 4.2.3 版创建的。
在 TypeScript 中创建枚举
在本节中,我们将运行一个同时声明数字枚举和字符串枚举的示例。
TypeScript 中的枚举通常用于表示给定值的确定数量的选项。这些数据排列在一组键/值对中。虽然键必须是字符串,与一般的 JavaScript 对象一样,枚举成员的值通常是自动递增的数字,主要用于区分一个成员和另一个成员。只有数字值的枚举称为数字枚举。
要创建数字枚举,请使用 enum 关键字,后跟enum 的名称。然后创建一个花括号 ({}) 块,我们将在其中指定enum成员,如下所示:
enum CardinalDirection {
North = 1,
East,
South,
West,
};
在此示例中,我们正在创建一个名为 CardinalDirection 的枚举,它有一个代表每个基本方向的成员。
我们使用数字 1 作为 CardinalDirection 枚举的第一个成员的值。这将数字 1 指定为 North 的值。但是,我们没有将值分配给其他成员。这是因为 TypeScript 自动将剩余成员设置为前一个成员的值加一。CardinalDirection.East 的值为 2,CardinalDirection.South 的值为 3,CardinalDirection.West 的值为 4。
此行为仅适用于每个成员只有数字值的数字枚举。
我们也可以完全忽略设置枚举成员的值:
enum CardinalDirection {
North,
East,
South,
West,
};
在这种情况下,TypeScript 会将第一个成员设置为 0,然后,根据该成员自动设置其他成员,每个成员递增 1。这将产生与以下相同的代码:
enum CardinalDirection {
North= 0,
East= 1,
South= 2,
West= 3,
};
TypeScript 编译器默认为枚举成员分配数字,但我们可以覆盖它以生成字符串枚举。这些是每个成员都有字符串值的枚举;当值需要具有某种人类可读的含义时,这些很有用,例如,如果我们稍后需要读取日志或错误消息中的值。
我们可以使用以下代码将枚举成员声明为具有字符串值:
enum CardinalDirection {
North = 'N',
East = 'E',
South = 'S',
West = 'W'
}
现在每个方向都有一个字母值,指示它们绑定到哪个方向。
通过涵盖声明语法,我们现在可以查看底层 JavaScript 以了解有关枚举行为方式的更多信息,包括键/值对的双向特性。
双向枚举成员
在 TypeScript 编译后,枚举被转换为 JavaScript 对象。但是,枚举有一些特性可以将它们与对象区分开来。它们为存储常量成员提供了比传统 JavaScript 对象更稳定的数据结构,并且还为枚举成员提供了双向引用。为了展示它是如何工作的,本节将向我们展示 TypeScript 如何在最终代码中编译枚举。
获取我们在上一节中创建的字符串枚举:
enum CardinalDirection {
North = 'N',
East = 'E',
South = 'S',
West = 'W',
};
当使用 TypeScript 编译器编译为 JavaScript 时,这将变成以下代码:
"use strict";
var CardinalDirection;
(function (CardinalDirection) {
CardinalDirection["North"] = "N";
CardinalDirection["East"] = "E";
CardinalDirection["South"] = "S";
CardinalDirection["West"] = "W";
})(CardinalDirection || (CardinalDirection = {}));
在这段代码中,“use strict”字符串启动了严格模式,这是一种更严格的 JavaScript 版本。之后,TypeScript 创建一个没有值的变量 CardinalDirection。然后,代码包含一个立即调用的函数表达式 (IIFE),它将 CardinalDirection 变量作为参数,同时,还将其值设置为空对象 ({})(如果尚未设置)。
在函数内部,一旦将 CardinalDirection 设置为空对象,代码就会为该对象分配多个属性:
"use strict";
var CardinalDirection;
(function (CardinalDirection) {
CardinalDirection["North"] = "N";
CardinalDirection["East"] = "E";
CardinalDirection["South"] = "S";
CardinalDirection["West"] = "W";
})(CardinalDirection || (CardinalDirection = {}));
请注意,每个属性都是原始枚举的一个成员,其值设置为枚举的成员值。
对于字符串枚举,这是过程的结束。但是,接下来,我们将尝试使用上一节中的数字枚举进行相同的操作:
enum CardinalDirection {
North = 1,
East,
South,
West,
};
这将产生以下代码,并添加了突出显示的部分:
"use strict";
var CardinalDirection;
(function (CardinalDirection) {
CardinalDirection[CardinalDirection["North"] = 1] = "North";
CardinalDirection[CardinalDirection["East"] = 2] = "East";
CardinalDirection[CardinalDirection["South"] = 3] = "South";
CardinalDirection[CardinalDirection["West"] = 4] = "West";
})(CardinalDirection || (CardinalDirection = {}));
除了枚举的每个成员都成为对象的属性 (CardinalDirection["North"] = 1]) 之外,枚举还为每个数字创建一个键并将字符串分配为值。 对于 North,CardinalDirection["North"] = 1 返回值 1,CardinalDirection[1] = "North" 将值 "North" 分配给键 "1"。
这允许在数字成员的名称和它们的值之间建立双向关系。 要对此进行测试,请记录以下内容:
console.log(CardinalDirection.North)
这将返回“North”键的值:
Output 1
接下来,运行以下代码来反转引用的方向:
console.log(CardinalDirection[1])
这将输出:
Output "North"
为了说明代表枚举的最终对象,请将整个枚举记录到控制台:
console.log(CardinalDirection)
这将显示创建双向效果的两组键/值对:
Output{
"1": "North",
"2": "East",
"3": "South",
"4": "West",
"North": 1,
"East": 2,
"South": 3,
"West": 4
}
了解了枚举在 TypeScript 中是如何工作的,现在,我们将继续使用枚举在代码中声明类型。
在 TypeScript 中使用枚举
在本节中,我们将尝试在 TypeScript 代码中将枚举成员分配为类型的基本语法。 这可以通过与声明基本类型相同的方式来完成。
要将 CardinalDirection 枚举用作 TypeScript 中变量的类型,可以使用枚举名称,如以下突出显示的代码所示:
enum CardinalDirection {
North = 'N',
East = 'E',
South = 'S',
West = 'W',
};
const direction: CardinalDirection = CardinalDirection.North;
请注意,我们将变量设置为将枚举作为其类型:
const direction: CardinalDirection= CardinalDirection.North;
我们还将变量值设置为枚举的成员之一,在本例中为 CardinalDirection.North。 您可以这样做,因为枚举被编译为 JavaScript 对象,因此它们除了作为类型之外还具有值表示。
如果传递的值与方向变量的枚举类型不兼容,如下所示:
const direction: CardinalDirection = false;
TypeScript 编译器将显示错误 2322:
OutputType 'false' is not assignable to type 'CardinalDirection'. (2322)
因此,方向只能设置为 CardinalDirection 枚举的成员。
我们还可以将变量的类型设置为特定的枚举成员:
enum CardinalDirection {
North = 'N',
East = 'E',
South = 'S',
West = 'W',
};
const direction: CardinalDirection.North= CardinalDirection.North;
在这种情况下,该变量只能分配给 CardinalDirection 枚举的 North 成员。
如果我们的枚举成员具有数值,我们还可以将变量的值设置为这些数值。 例如,给定枚举:
enum CardinalDirection {
North = 1,
East,
South,
West,
};
我们可以将 CardinalDirection 类型的变量的值设置为 1:
const direction: CardinalDirection = 1;
这是可能的,因为 1 是 CardinalDirection 枚举的 North 成员的值。 这仅适用于枚举的数字成员,它依赖于编译后的 JavaScript 对数字枚举成员的双向关系,在最后一节中介绍。
现在,我们已经尝试使用枚举值声明变量类型,下一节将演示一种操作枚举的特定方法:提取底层对象类型。
提取枚举的对象类型
在前面的部分中,我们发现枚举不仅是 JavaScript 之上的类型级扩展,而且具有实际值。 这也意味着枚举数据结构本身具有类型,如果,我们尝试设置表示枚举实例的 JavaScript 对象,则必须考虑到该类型。 为此,我们需要提取枚举对象表示本身的类型。
给定的 CardinalDirection 枚举:
enum CardinalDirection {
North = 'N',
East = 'E',
South = 'S',
West = 'W',
};
尝试创建一个与我们枚举匹配的对象,如下所示:
enum CardinalDirection {
North = 'N',
East = 'E',
South = 'S',
West = 'W',
};
const test1: CardinalDirection = {
North: CardinalDirection.North,
East: CardinalDirection.East,
South: CardinalDirection.South,
West: CardinalDirection.West,
}
在这段代码中,test1 是一个 CardinalDirection 类型的对象,对象值包含了枚举的所有成员。 但是,TypeScript 编译器将显示错误 2322:
OutputType '{ North: CardinalDirection; East: CardinalDirection; South: CardinalDirection; West: CardinalDirection; }' is not assignable to type 'CardinalDirection'.
出现此错误的原因是 CardinalDirection 类型表示所有枚举成员的联合类型,而不是枚举对象本身的类型。
我们可以在枚举名称之前使用 typeof 来提取对象类型。 检查下面突出显示的代码:
enum CardinalDirection {
North = 'N',
East = 'E',
South = 'S',
West = 'W',
};
const test1: typeof CardinalDirection = {
North: CardinalDirection.North,
East: CardinalDirection.East,
South: CardinalDirection.South,
West: CardinalDirection.West,
}
TypeScript 编译器现在将能够正确编译代码。
本节展示了一种扩展枚举使用的特定方法。接下来,我们将研究一个适用于枚举的用例:游戏开发中的位标志。
使用带有 TypeScript 枚举的位标志
在本教程的最后一部分中,我们将了解 TypeScript 中枚举的具体用例:位标志。
位标志是一种通过使用按位运算将不同的类似布尔值的选项表示为单个变量的方法。为此,每个标志必须使用 32 位数字中的一位,因为这是 JavaScript 在执行按位运算时允许的最大值。最大 32 位数为 2,147,483,647,二进制为 1111111111111111111111111111111,因此,我们有 31 个可能的标志。
假设,我们正在构建一个游戏,玩家可能有不同的技能,例如 SKILL_A、SKILL_B 和 SKILL_C。为了确保我们的程序知道玩家何时具有某种技能,我们可以根据玩家的状态制作可以打开或关闭的标志。
使用以下伪代码,给每个技能标志一个二进制值:
SKILL_A = 0000000000000000000000000000001
SKILL_B = 0000000000000000000000000000010
SKILL_C = 0000000000000000000000000000100
现在,我们可以使用按位运算符 | 将玩家的所有当前技能存储在一个变量中。 (要么):
playerSkills = SKILL_A | SKILL_B
在这种情况下,为玩家分配位标志 0000000000000000000000000000001 和位标志 0000000000000000000000000000010 运算符将产生 0000000000000000000000000000011,这将代表玩家拥有两种技能。
我们还可以添加更多技能:
playerSkills |= SKILL_C
这将产生 0000000000000000000000000000111 表示玩家拥有所有三个技能。
我们还可以使用按位运算符 & (AND) 和 ~ (NOT) 的组合删除技能:
playerSkills &= ~SKILL_C
然后要检查玩家是否具有特定技能,请使用按位运算符 & (AND):
hasSkillC = (playerSkills & SKILL_C) == SKILL_C
如果玩家没有 SKILL_C 技能,则 (playerSkills & SKILL_C) 部分将评估为 0。否则 (playerSkills & SKILL_C) 评估为我们正在测试的技能的确切值,在这种情况下为 SKILL_C (0000000000000000000000000000010 )。 通过这种方式,我们可以测试评估值是否与我们正在测试它的技能的值相同。
由于 TypeScript 允许我们将枚举成员的值设置为整数,因此,我们可以将这些标志存储为枚举:
enum PlayerSkills {
SkillA = 0b0000000000000000000000000000001,
SkillB = 0b0000000000000000000000000000010,
SkillC = 0b0000000000000000000000000000100,
SkillD = 0b0000000000000000000000000001000,
};
我们可以使用前缀 0b 直接表示二进制数。 如果我们不想使用如此大的二进制表示,可以使用按位运算符 <<(左移):
enum PlayerSkills {
SkillA = 1 << 0,
SkillB = 1 << 1,
SkillC = 1 << 2,
SkillD = 1 << 3,
};
1 << 0将评估到0b0000000000000000000000000000001、1 << 1到0b0000000000000000000000000000010、1 << 2到0b0000000000000000000000000000100和1 << 3到0b0000000000000000000000000001000。
现在,我们可以像这样声明 playerSkills 变量:
let playerSkills: PlayerSkills = PlayerSkills.SkillA | PlayerSkills.SkillB;
注意:必须将 playerSkills 变量的类型显式设置为 PlayerSkills,否则 TypeScript 会推断它为 number 类型。
要添加更多技能,我们将使用以下语法:
playerSkills |= PlayerSkills.SkillC;
我们还可以删除技能:
playerSkills &= ~PlayerSkills.SkillC;
最后,我们可以使用枚举检查玩家是否有任何给定的技能:
const hasSkillC = (playerSkills & PlayerSkills.SkillC) === PlayerSkills.SkillC;
虽然,仍在底层使用位标志,但该解决方案提供了一种更具可读性和组织性的方式来显示数据。 它还通过将二进制值作为常量存储在枚举中,并在 playerSkills 变量与位标志不匹配时抛出错误,从而使我们的代码更加类型安全。
总结
在大多数提供类型系统的语言中,枚举是一种常见的数据结构,这在 TypeScript 中没有什么不同。
在本节教程中,我们在 TypeScript 中创建和使用了枚举,同时还经历了一些更高级的场景,例如,提取枚举的对象类型和使用位标志。 使用枚举,我们可以使代码库更具可读性,同时,还将常量组织到数据结构中,而不是将它们留在全局空间中。
相关推荐
- Html中Css样式Ⅱ_html+css+
-
元素的定位(方式五种定位方式):静态定位:position:static;相对定位:position:relative;绝对定位:position:absolute;固定定位:position...
- HTML 标签和属性值的基本格式_html标签及属性的语法规则
-
HTML:HyperTextMarkupLanguage超文本标记语言HTML代码不区分大小写,包括HTML标记、属性、属性值都不区分大小写;任何空格或回车键在代码中都无效,插入空格或回车有...
- C#中使用Halcon开发视觉检测程序教程
-
一、环境准备1.安装Halcon从Halcon官方网站下载适合你操作系统的安装包,按照安装向导完成安装。安装过程中,记住安装路径,后续配置环境时会用到。2.配置VisualStudio项目打开V...
- 【开源】C#功能强大,灵活的跨平台开发框架 - Uno Platform
-
前言今天给广大网友分享一个基于C#开源、功能强大、灵活的跨平台开发框架,她就是:UnoPlatform。通过UnoPlatform,开发者可以利用单一代码库实现多平台兼容,极大地提高了开发效率和...
- C# 的发展简史_c#的发展前景
-
1.C#的诞生和初期(2000-2005)2000年:在微软的PDC大会上,由AndersHejlsberg首次公开展示了C#语言。2002年:微软发布了.NETFramework1.0,其...
- Visual Studio 2010-C#跟西门子1200(Sharp7)窗体控制②-启动按钮
-
VisualStudio2010--C#跟西门子1200(Sharp7)窗体控制②--启动按钮上期回顾(上期主要是新建窗体应用程序,添加sharp7的类库并引用,建立一个button按钮):本期将...
- Visual Studio窗口布局混乱后的恢复与优化指南
-
在使用VisualStudio进行开发时,我们常因误操作(如拖拽窗口、关闭面板、多显示器切换)导致界面布局混乱,代码编辑器、解决方案资源管理器、属性面板等组件“错位”,严重影响开发效率。本文将针对布...
- 使用Visual Studio 2017为AutoCAD创建一个c#模板
-
本教程的目标是展示如何在VisualStudio2017中创建AutoCAD的c#项目模板,该模板允许在调试模式下从VisualStudio加载DLL来自动启动AutoCAD。本文展示的示例使用...
- IT科技-续3Visual Studio2019-C#实战练习
-
上次完成了登录页面的窗体设计,本次完成管理界面的设计。第一步ComBox控制深度操作点击编辑选项,加入预定选项,完成操作。第二步复制Buttons控件依次为保存、删除、重置、编辑按钮属性设置,参考...
- 如何在 C# 中将文本转换为 Word 以及将 Word 转换为文本
-
在现代软件开发中,处理文档内容是一个非常常见的需求。无论是生成报告、存储日志,还是处理用户输入,开发者都可能需要在纯文本与Word文档之间进行转换。有时需要将文本转换为Word,以便生成结构化的...
- 简短的C#入门教程 # C# 入门教程 C#(读作...
-
简短的C#入门教程#C#入门教程C#(读作CSharp)是一种由Microsoft开发的多范式编程语言,它具有广泛的应用,特别是在Windows平台上。本教程将介绍C#的基础知识,以帮助您入门这...
- JavaScript中this指向各种场景_前端中this的指向
-
在JavaScript中,this的指向是一个核心概念,其值取决于函数的调用方式,而非定义位置(箭头函数除外)。以下是this指向的常见场景及具体说明:1.全局作用域中的this在全局作用域(非...
- 微信WeUI设计规范文件下载及使用方法
-
来人人都是产品经理【起点学院】,BAT实战派产品总监手把手系统带你学产品、学运营。WeUI是一套同微信原生视觉体验一致的基础样式库,由微信官方设计团队为微信Web开发量身设计,可以令用户的使用感知...
- JavaScript技术:如何动态添加事件?
-
随着前端技术的不断发展,JavaScript已经成为了不可或缺的一部分,它可以让网页变得更加流畅和美观。但是,在JavaScript中动态添加事件还是一个比较困难的问题,为此,本文将从入门到精通,介绍...
- 一周热门
-
-
【验证码逆向专栏】vaptcha 手势验证码逆向分析
-
Python实现人事自动打卡,再也不会被批评
-
Psutil + Flask + Pyecharts + Bootstrap 开发动态可视化系统监控
-
一个解决支持HTML/CSS/JS网页转PDF(高质量)的终极解决方案
-
再见Swagger UI 国人开源了一款超好用的 API 文档生成框架,真香
-
网页转成pdf文件的经验分享 网页转成pdf文件的经验分享怎么弄
-
C++ std::vector 简介
-
飞牛OS入门安装遇到问题,如何解决?
-
系统C盘清理:微信PC端文件清理,扩大C盘可用空间步骤
-
10款高性能NAS丨双十一必看,轻松搞定虚拟机、Docker、软路由
-
- 最近发表
-
- Html中Css样式Ⅱ_html+css+
- HTML 标签和属性值的基本格式_html标签及属性的语法规则
- 基于Visual Studio C#语言开发上位机,做定制设计后有多好看
- C#中使用Halcon开发视觉检测程序教程
- 【开源】C#功能强大,灵活的跨平台开发框架 - Uno Platform
- C# 的发展简史_c#的发展前景
- Visual Studio 2010-C#跟西门子1200(Sharp7)窗体控制②-启动按钮
- Visual Studio窗口布局混乱后的恢复与优化指南
- 使用Visual Studio 2017为AutoCAD创建一个c#模板
- IT科技-续3Visual Studio2019-C#实战练习
- 标签列表
-
- python判断字典是否为空 (50)
- crontab每周一执行 (48)
- aes和des区别 (43)
- bash脚本和shell脚本的区别 (35)
- canvas库 (33)
- dataframe筛选满足条件的行 (35)
- gitlab日志 (33)
- lua xpcall (36)
- blob转json (33)
- python判断是否在列表中 (34)
- python html转pdf (36)
- 安装指定版本npm (37)
- idea搜索jar包内容 (33)
- css鼠标悬停出现隐藏的文字 (34)
- linux nacos启动命令 (33)
- gitlab 日志 (36)
- adb pull (37)
- python判断元素在不在列表里 (34)
- python 字典删除元素 (34)
- vscode切换git分支 (35)
- python bytes转16进制 (35)
- grep前后几行 (34)
- hashmap转list (35)
- c++ 字符串查找 (35)
- mysql刷新权限 (34)