TypeScript枚举类型应用:前后端状态码映射的最简方案
介绍
这篇文章来谈一下 TypeScript 中的枚举类型(Enum)以及一些最佳实践。事情的起因是这样的,今天看到自己之前写的一段代码,感觉不是很好,于是想优化一下,期间用到了枚举类型,遂记录一下。为了方便理解,我将原来的例子简化一下。
业务需求
业务需求是这样的:我们要实现一个Job系统,你可以将其想象为Jenkins Job类似的东西,每个Job有一个状态,状态可以是以下几种:
PENDING:等待执行RUNNING:正在执行SUCCESS:执行成功FAILED:执行失败CANCELED:执行被取消
Job的状态信息由后端返回,前端只负责展示,也不需要实时刷新。很简单的需求,对吧?我的原始代码如下:
原始代码
前端数据类型定义, 首先定义一个字面量用来保存Job状态,然后定义一个Job接口来描述Job对象。
// 定义Job状态字面量
type JobStatus = 'PENDING' | 'RUNNING' | 'SUCCESS' | 'FAILED' | 'CANCELED';
// 每个Job包含id、name和status三个属性
interface Job {
id: string;
name: string;
status: JobStatus;
}
后端返回数据如下,可以看到后端是用数字类型来表示状态的。
const jobData = [
{ id: '1', name: 'Job 1', status: 1 }, // PENDING
{ id: '2', name: 'Job 2', status: 2 }, // RUNNING
{ id: '3', name: 'Job 3', status: 3 }, // SUCCESS
{ id: '4', name: 'Job 4', status: 4 }, // FAILED
{ id: '5', name: 'Job 5', status: 5 }, // CANCELED
];
为了将后端返回的数字类型和前端定义的Job Status对应起来,我又额外写了一个映射函数:
function mapJobStatus(status: number): JobStatus {
switch (status) {
case 1:
return 'PENDING';
case 2:
return 'RUNNING';
case 3:
return 'SUCCESS';
case 4:
return 'FAILED';
case 5:
return 'CANCELED';
default:
throw new Error(`Unknown status: ${status}`);
}
}
接下来就是展示了,展示Job状态时,用户不想看到全大写的状态,而是想看到首字母大写的状态,所以我又写了一个函数来处理这个问题:
function getJobDisplayName(status: JobStatus): string {
return status.charAt(0).toUpperCase() + status.slice(1).toLowerCase();
}
/* 转换后的状态字符串如下:
PENDING -> Pending
RUNNING -> Running
SUCCESS -> Success
FAILED -> Failed
CANCELED -> Canceled
*/
好了,下面我们停下来思考一下,以上这些代码都解决了哪些问题,为什么需要两个转换函数,有没有更好的解决方式?
问题分析
为了完成这个需求,上述代码做了以下几件事:
- 后端状态码到前端状态的转换(1,2,3,4,5 -> PENDING, RUNNING, SUCCESS, FAILED, CANCELED)
- 前端状态字面量到展示字符串的转换(PENDING, RUNNING, SUCCESS, FAILED, CANCELED -> Pending, Running, Success, Failed, Canceled)
对于第一点,可以使用枚举类型来实现,这样就不需要手动维护状态码和状态字面量之间的映射关系了。
对于第二点,原本的实现是将全大写的状态转换为首字母大写的形式,这种转换方式比较简单,但实际业务中,可能会有更复杂的需求,比如用户希望看到不同的展示字符串(例如将RUNNING显示为In progress)。因此,使用一个映射表来处理这种转换会更加灵活。
优化后的代码
我们可以使用 TypeScript 的枚举类型来简化代码。首先定义一个枚举来表示 Job 状态:
enum JobStatus {
PENDING = 1,
RUNNING = 2,
SUCCESS = 3,
FAILED = 4,
CANCELED = 5,
}
这样就可以省去第一个转换函数mapJobStatus,因为枚举本身就提供了状态码到状态字面量的映射,可以直接使用这个枚举来定义 Job 接口:
interface Job {
id: string;
name: string;
status: JobStatus; // 使用枚举类型
}
接下来,重写getJobDisplayName, 这里使用typescript的Record类型来创建一个映射表(Record类型相当于一个键值对的映射,只不过键和值都是类型化的),将枚举值映射到展示字符串,与原本的实现方式相比,这种方式更加简洁易维护。
const getJobDisplayName: Record<JobStatus, string> = {
[JobStatus.PENDING]: 'Pending',
[JobStatus.RUNNING]: 'In progress',
[JobStatus.SUCCESS]: 'Success',
[JobStatus.FAILED]: 'Failed',
[JobStatus.CANCELED]: 'Canceled',
};
最后是调用代码,如下:
const jobs = [
{ id: '1', name: 'Job 1', status: 1 },
{ id: '2', name: 'Job 2', status: 2 },
{ id: '3', name: 'Job 3', status: 3 },
{ id: '4', name: 'Job 4', status: 4 },
{ id: '5', name: 'Job 5', status: 5 },
];
jobs.forEach((job) => {
console.log(
`Job ID: ${job.id}, Name: ${job.name}, Status: ${
getJobDisplayName[job.status as JobStatus]
}`
);
});
使用枚举类型的好处是:
- 可读性:枚举提供了更清晰的语义,
- 类型安全:TypeScript 的枚举类型可以确保状态值的合法性,避免了手动维护映射关系的错误。
- 简化代码:减少了转换函数的数量,使代码更简洁
- 易于维护:如果需要添加新的状态,只需在枚举中添加即可,不需要修改多个地方。
有没有更好的实现方式?很想听听大家的想法,欢迎留言讨论。
今天就到这里了,我们明天见。
TypeScript枚举类型应用:前后端状态码映射的最简方案的更多相关文章
- typescript枚举,类型推论,类型兼容性,高级类型,Symbols(学习笔记非干货)
枚举部分 Enumeration part 使用枚举我们可以定义一些有名字的数字常量. 枚举通过 enum关键字来定义. Using enumerations, we can define some ...
- TypeScript——枚举类型
enum类型是对JavaScript标准数据类型的一个补充. 在运行环境下编译成对象, 可用属性名索引, 也可用属性值索引.而其实现原理为:反向映射 (如下例) 数字枚举 enum Role { ...
- django开发最完美手机购物商城APP带前后端源码
后端和数据接口,全采用django开发 从0到大神的进阶之路 一句话,放弃单文件引用vue.js练手的学习方式 马上从vue-cli4练手,要不然,学几年,你也不懂组件式开发,不懂VUEX,不懂路由, ...
- 微信公众号商城、小程序商城、H5商城 实例 前后端源码
CRMEB客户管理+电商营销系统 https://gitee.com/ZhongBangKeJi/CRMEB 演示站后台: http://demo.crmeb.net/admin 账号:demo 密 ...
- 【vue3-element-admin 】基于 Vue3 + Vite4 + TypeScript + Element-Plus 从0到1搭建后台管理系统(前后端开源@有来开源组织)
vue3-element-admin 是基于 vue-element-admin 升级的 Vue3 + Element Plus 版本的后台管理前端解决方案,技术栈为 Vue3 + Vite4 + T ...
- TypeScript 中枚举类型的理解?应用场景?
一.是什么 枚举是一个被命名的整型常数的集合,用于声明一组命名的常数,当一个变量有几种可能的取值时,可以将它定义为枚举类型 通俗来说,枚举就是一个对象的所有可能取值的集合 在日常生活中也很常见,例如表 ...
- .net工具类 获取枚举类型的描述
一般情况我们会用枚举类型来存储一些状态信息,而这些信息有时候需要在前端展示,所以需要展示中文注释描述. 为了方便获取这些信息,就封装了一个枚举扩展类. /// <summary> /// ...
- 前后端分离djangorestframework——restful规范
restful现在非常流行,所以很有必要提一下 web服务交互 在浏览器中能看到的每个网站,都是一个web服务.那么我们在提供每个web服务的时候,都需要前后端交互,前后端交互就一定有一些实现方案,我 ...
- 使用 Nginx 部署前后端分离项目,解决跨域问题
前后端分离这个问题其实松哥和大家聊过很多了,上周松哥把自己的两个开源项目部署在服务器上以帮助大家可以快速在线预览(喜大普奔,两个开源的 Spring Boot + Vue 前后端分离项目可以在线体验了 ...
- http 状态码含义
HTTP状态码被分为五大类, 目前我们使用的HTTP协议版本是1.1, 支持以下的状态码.随着协议的发展,HTTP规范中会定义更多的状态码. 小技巧: 假如你看到一个状态码518, 你并不知道具体51 ...
随机推荐
- java程序乱码问题
1.字符编码简介 字符编码从字面上理解,就是将字符编码为由多个bits(0或1)组成的字节序列.但字符和字节序列的映射并不是直接的,可简要概括为2个步骤,第1步由字符映射到unicode码,第2步由u ...
- 100行代码实现Chat2XX(DB/ Web/ KnowledgeBase)
这两年基于大模型的应用可谓五花八门,Chat2DB,Chat2Web,Chat2KnowledgeBase,Chat2XXX等等.本质上都是以自然语言作为系统输入,通过各种手段获取额外的上下文信息,然 ...
- cmd /k 解决cmd命令闪退问题
cmd /k 的含义是执行后面的命令,并且执行完毕后保留窗口. & 是连接多条命令.PAUSE 表示运行结束后暂停,等待一个任意按键.EXIT 表示关闭命令行窗口.如果使用 cmd /c 就可 ...
- 6.4K star!轻松搞定专业领域大模型推理,这个知识增强框架绝了!
嗨,大家好,我是小华同学,关注我们获得"最新.最全.最优质"开源项目和高效工作学习方法 「垂直领域大模型落地难?逻辑推理总出错?这个来自OpenSPG的开源框架,让专业领域知识服务 ...
- 通过SpringBoot配置文件配置Druid数据源
目录 引入坐标依赖 配置application.properties文件 新建一个controller观察使用的是哪一个数据源 在SpringBoot 1.X 中,spring-boot-starte ...
- Python基础 - 微线程
也是多任务系列哦, 进程, 线程, 微线程, 这样一来, 对于多任务这个话题, 应该算是有所涉猎了吧. 我也不怎用其实. 微线程, 就是在 单线程的前提下, 完成多任务, 多任务按照一定顺序交替执行. ...
- MFC单文档应用程序引入GDI+
在MFC中引入GDI+,步骤如下: 1.在需要用到GDI+的文件中添加GDI+文件 1 #include <gdiplus.h> 2 using namespace Gdiplus; 2. ...
- TVM: Device/Target Interactions
任何新的运行时环境都必须实现三个主要方面: DeviceAPI类为特定设备提供了一个句柄,以及用于与之交互的API.它定义了一个通用接口,用于查询设备参数(例如可用内存.线程数量等)和执行简单操作(例 ...
- 鸿蒙版微信小程序不可用,一文告诉你10分钟修复
鸿蒙版微信小程序不可用,一文告诉你10分钟修复 最近是否有人反馈微信小程序不可用或者界面异常,比如: 而开发者可能比较困惑,我的代码一直都没有更新过,为什么最近突然这么多报障的了? 其实很有可能反馈者 ...
- Spring Boot 整合Redisson操作Redis基础篇
<Spring Boot 整合Redisson配置篇> <Spring Boot 整合Redisson操作Redis基础篇> <Redisson批量操作类RBuckets ...