别再写 TypeScript enum了!新枚举方式让 bundle 瞬间小20%

前几天排查项目性能问题,发现一个让人哭笑不得的情况。光是TypeScriptenum就占了打包体积的相当一部分!

同事小张一脸无辜地说:"我用enum不是为了类型安全嘛..."

没错,enum确实能保证类型安全,但代价有点大了!我尝试了一种新方法后,打包体积直接减少了20%,而且类型安全一点都没少!

为什么不用enum?

先看个我们项目里的真实例子:

typescript 复制代码
// 以前的写法 - enum
enum UserRole {
  Admin = 'admin',
  User = 'user',
  Guest = 'guest',
  // ...后面还有十来个角色
}

// 使用的时候
const role = UserRole.Admin

看起来很正常对不对?但你知道编译成JavaScript后发生了什么吗?

javascript 复制代码
// 编译后的代码
var UserRole;
(function (UserRole) {
    UserRole["Admin"] = "admin";
    UserRole["User"] = "user";
    UserRole["Guest"] = "guest";
    // ...每个值都会生成对应的代码
})(UserRole || (UserRole = {}));

每个enum都会变成一个立即执行函数,项目里enum越多,生成的代码就越多,打包体积自然就膨胀了。

新的解决方案:常量对象 + 类型别名

来看看我是怎么改造的:

typescript 复制代码
// 新写法 - 常量对象
const UserRole = {
  Admin: 'admin',
  User: 'user',
  Guest: 'guest',
} as const  // as const很重要,让TypeScript知道这是只读的

// 类型别名 - 相当于枚举的类型!
type UserRole = keyof typeof UserRole

// 使用时的方式完全一样!
const role: UserRole = UserRole.Admin

as const是关键!它告诉TypeScript:"这个对象的值都是固定的,不可用动!"

类型别名是什么意思?

类型别名就是给类型起个新名字,比如这里的type UserRole = keyof typeof UserRole,意思是:

  • typeof UserRole:获取UserRole对象的类型
  • keyof:取这个对象的所有键(Key)
  • 所以最终UserRole类型就是"Admin" | "User" | "Guest"这样的联合类型

写代码会有枚举一样的提示吗?

有的!完全一样! 当你输入UserRole.的时候,VSCode还是会自动提示AdminUserGuest,和用enum时一模一样。

编译后发生了什么?

javascript 复制代码
// 编译后的代码 - 简洁多了!
const UserRole = {
    Admin: 'admin',
    User: 'user',
    Guest: 'guest',
}

就这么简单! 没有额外的函数,没有运行时开销,就是普通的对象字面量。

实际效果

在我们项目中,替换了所有的enum

改造前: 打包体积:1.2MB,enum数量:27个 改造后: 打包体积:960KB,enum数量:0个

体积直接减少了20%! 而且代码提示、类型检查完全没受影响。

再来看看几个案例

1. 页面状态管理

typescript 复制代码
// 替换前
enum PageStatus {
  Loading = 'loading',
  Success = 'success',
  Error = 'error',
  Empty = 'empty'
}

// 替换后
const PageStatus = {
  Loading: 'loading',
  Success: 'success',
  Error: 'error',
  Empty: 'empty'
} as const
type PageStatus = keyof typeof PageStatus

// 使用体验完全一致!
function renderPage(status: PageStatus) {
  // ...
}

renderPage(PageStatus.Loading) // ✅ 代码提示依旧完美

2. 主题配置

typescript 复制代码
// 主题配置
const Theme = {
  Light: 'light',
  Dark: 'dark',
  Auto: 'auto'
} as const
type Theme = keyof typeof Theme

// 使用时照样有提示
function setTheme(theme: Theme) {
  console.log(`切换至${theme}主题`)
}

setTheme(Theme.Dark) // ✅ 输入Theme.就会自动提示

3. API错误码

typescript 复制代码
// 错误码定义
const ErrorCode = {
  NotFound: 404,
  Unauthorized: 401,
  ServerError: 500
} as const
type ErrorCode = typeof ErrorCode[keyof typeof ErrorCode]

// 使用
if (error.code === ErrorCode.NotFound) {
  // 处理404错误
}

需要注意的地方

虽然这个方案很好,但有两点要注意:

数字枚举需要稍作调整

typescript 复制代码
const StatusCode = {
  Ok: 200,
  NotFound: 404
} as const
type StatusCode = typeof StatusCode[keyof typeof StatusCode]

如果需要反向映射(根据值找键),需要自己写工具函数

typescript 复制代码
function getKeyByValue(obj: any, value: any) {
  return Object.keys(obj).find(key => obj[key] === value)
}

或者还是直接用枚举

typescript 复制代码
enum Status {
  Draft = 1,
  Published = 2
}

const statusName = Status[1] // 返回 "Draft"

总结

简单来说就是:

  • const obj = { ... } as const代替enum
  • type Key = keyof typeof obj定义类型
  • 打包体积能小很多,构建速度也更快,代码更简洁

PS :这个方法需要TypeScript 3.4+版本支持。

觉得有帮助的话,点个收藏分享给更多小伙伴吧~还有什么问题欢迎留言讨论!

我是大华,专注分享前后端开发的实战笔记。关注我,少走弯路,一起进步!

📌往期精彩

《工作 5 年没碰过分布式锁,是我太菜还是公司太稳?网友:太真实了!》

《写给小公司前端的 UI 规范:别让页面丑得自己都看不下去》

《只会写 Mapper 就敢说会 MyBatis?面试官:原理都没懂》

《别学23种了!Java项目中最常用的6个设计模式,附案例》

《Vue3+TS设计模式:5个真实场景让你代码更优雅》

相关推荐
方安乐2 小时前
vite+vue+js项目使用ts报错
前端·javascript·vue.js
njsgcs2 小时前
网页连接摄像头
javascript·css·html
李明卫杭州2 小时前
JavaScript 中的各种取整方式详解
javascript
子兮曰2 小时前
🚀别再乱写package.json了!这些隐藏技巧让项目管理效率提升300%
前端·javascript·npm
我叫汪枫3 小时前
Spring Boot图片验证码功能实现详解 - 从零开始到完美运行
java·前端·javascript·css·算法·html
小桥风满袖3 小时前
极简三分钟ES6 - ES8中async,await
前端·javascript
一直在学习的小白~3 小时前
node_modules 明明写进 .gitignore,却还是被 push/commit 的情况
前端·javascript·vue.js
nightunderblackcat4 小时前
新手向:从零理解LTP中文文本处理
前端·javascript·easyui
User:你的影子4 小时前
WPF ItemsControl 绑定
开发语言·前端·javascript