前几天检查项目性能时,我发现一个令人意外的情况。TypeScript的enum语法竟然占据了打包体积的相当大部分!有个同事有些无奈地说:“我用enum只是为了确保类型安全啊...”
enum确实能提供类型安全,但代价太大了。当我尝试了一种新方法后,打包体积直接减少了20%,而且完全没有损失类型安全性。
先看一个实际项目中的例子:
// 原来的enum写法
enum UserRole {
Admin = 'admin',
User = 'user',
Guest = 'guest',
// 还有更多角色定义
}
// 使用方式
const role = UserRole.Admin
这段代码看起来很普通,但编译后的JavaScript却变得复杂:
// 编译后的代码
var UserRole;
(function (UserRole) {
UserRole["Admin"] = "admin";
UserRole["User"] = "user";
UserRole["Guest"] = "guest";
// 每个值都会生成对应的代码
})(UserRole || (UserRole = {}));
每个enum都会变成一个立即执行函数。项目中enum数量越多,生成的代码就越多,打包体积自然就变大了。
我采用了新的写法来优化:
// 新写法 - 常量对象
const UserRole = {
Admin: 'admin',
User: 'user',
Guest: 'guest',
} as const // as const确保对象只读
// 类型别名 - 提供类型安全
type UserRole = keyof typeof UserRole
// 使用方式保持不变
const role: UserRole = UserRole.Admin
这里的as const很关键。它告诉TypeScript编译器:“这个对象的所有值都是固定的,不可修改”。
类型别名的作用是给类型起一个新名字。type UserRole = keyof typeof UserRole的含义是:
typeof UserRole:获取UserRole对象的类型
keyof:获取对象所有键名
最终UserRole类型就是"Admin" | "User" | "Guest"这样的联合类型
完全不受影响!当你输入UserRole.时,代码编辑器仍然会自动提示Admin、User、Guest等选项,与使用enum时完全一致。
新写法的编译结果非常简洁:
// 编译后的代码
const UserRole = {
Admin: 'admin',
User: 'user',
Guest: 'guest',
}
没有额外的函数,没有运行时开销,只是一个普通的对象字面量。
在我们的项目中,替换所有enum后:
改造前:打包体积1.2MB,enum数量27个
改造后:打包体积960KB,enum数量0个
体积减少了20%,而且类型检查和代码提示功能完全正常。
// 替换前
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) // 代码提示正常
// 主题配置
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.会自动提示
// 错误码定义
const ErrorCode = {
NotFound: 404,
Unauthorized: 401,
ServerError: 500
} as const
type ErrorCode = typeof ErrorCode[keyof typeof ErrorCode]
// 使用方式
if (error.code === ErrorCode.NotFound) {
// 处理404错误
}
虽然这个方案很好,但有几点需要注意:
数字枚举需要调整写法:
const StatusCode = {
Ok: 200,
NotFound: 404
} as const
type StatusCode = typeof StatusCode[keyof typeof StatusCode]
如果需要反向映射(根据值找键),需要自己编写工具函数:
function getKeyByValue(obj: any, value: any) {
return Object.keys(obj).find(key => obj[key] === value)
}
或者继续使用enum:
enum Status {
Draft = 1,
Published = 2
}
const statusName = Status[1] // 返回 "Draft"
优化方案很简单:
使用const obj = { ... } as const替代enum
使用type Key = keyof typeof obj定义类型
享受更小的打包体积、更快的构建速度和更简洁的代码
这种方法需要TypeScript 3.4及以上版本支持。对于大多数项目,这种优化能显著减少打包体积,提升应用性能,同时保持完整的类型安全特性。
扩展阅读:除了减少打包体积,这种写法还有助于Tree Shaking优化。因为常量对象是简单的数据结构,打包工具能更准确地分析哪些代码被使用,哪些可以被移除。这对于大型项目尤其重要,能进一步提升应用性能。
本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!
用for...in循环和Object.keys方法都可以获取对象的属性,那么它们有什么区别呢?getOwnPropertyNames方法输出的结果中还包含了对象的不可枚举属性,可以通过Object.propertyIsEnumerable来判断属性是否可枚举从而对结果进行过滤
在数学和计算机科学理论中,一个集的枚举是列出某些有穷序列集的所有成员的程序,或者是一种特定类型对象的计数。这两种类型经常(但不总是)重叠。
题目:在1,2,3,4,5 五个数中,我们随机选取 3个数。问有多少种取法?并且把每种取出数的方法列举出来。乍看这道题,其实感觉没什么难度。三个for循环不就解决问题了。
数字类型枚举:常规枚举的值都是数字类型,因此被称为数字类型枚举;改变与数字枚举关联的数字:默认情况下,第一个枚举值是 0,后续的值会递增。
枚举是对JavaScript标准数据类型集的扩充,常被用来限定在一定范围内取值的场景。在TypeScript中支持数字和字符串的枚举。我们可以用enum来实现。字符串枚举中没有自增的特性,我们在初始化的时候必须给每一个成员都设字符串。
在当前的javascript中,并没有枚举这个概念,在某些场景中使用枚举更能保证数据的正确性,减少数据校验过程,下面就介绍一下javascript如何模拟实现枚举效果。
使用枚举类型可以允许我们定义一些带名字的常量,也可以清晰地表达意图或创建一组有区别的用例。在 TypeScript 中,支持数字的和基于字符串的枚举。
枚举是受 TypeScript 支持的数据类型。枚举允许您定义一组命名常量。使用它们可以更轻松地记录意图或创建一组不同的案例。枚举大多数用于面向对象的编程语言(如 Java 和 C#)中
枚举的好处是,我们可以定义一些带名字的常量,而且可以清晰地表达意图或创建一组有区别的用例,TS支持数字的和基于字符串的枚举,首先来看数字枚举
假设有这样一个场景,我们需要统计员工的技术栈,目前我们需要标记的技术有 CSS、JavaScript、HTML、WebGL。然后我可以这样写枚举:
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!