一般 ts 项目不推荐使用 enum 的原因

示例代码
export const IntroduceShopSteps = {
CUSTOMIZE_SHOP: 'customize_shop',
ADD_MODULE: 'add_module',
PREVIEW_SHOP: 'preview_shop',
INTRODUCE_CONTENT_TABS: 'introduce_content_tabs',
} as const;

export type IntroduceShopSteps = (typeof IntroduceShopSteps)[keyof typeof IntroduceShopSteps];

你提供的写法(使用 as const 的对象字面量 + 类型提取)相比 TypeScript 的 enum 有以下几个主要优点:


✅ 1. 更符合 JavaScript 原生习惯,无运行时开销

  • enum 在编译后会生成额外的 JavaScript 代码(双向映射),增加 bundle 体积。
  • as const 对象是纯字面量,在运行时就是普通对象,零额外开销,尤其适合前端或对包大小敏感的场景。
// enum 编译后(反向映射)
var IntroduceShopSteps;
(function (IntroduceShopSteps) {
  IntroduceShopSteps["CUSTOMIZE_SHOP"] = "customize_shop";
  // ...
})(IntroduceShopSteps || (IntroduceShopSteps = {}));

而你的写法编译后就是:

export const IntroduceShopSteps = {
  CUSTOMIZE_SHOP: 'customize_shop',
  // ...
};

✅ 2. 字符串字面量类型更精确

  • 使用 as const 后,每个值都被推断为具体的字符串字面量类型(如 'customize_shop'),而不是宽泛的 string
  • 配合 type IntroduceShopSteps = (typeof ...)[keyof ...],你得到的是一个联合类型
  type IntroduceShopSteps = 'customize_shop' | 'add_module' | 'preview_shop' | 'introduce_content_tabs';

这比 enum 的成员类型(虽然也是字面量)在某些高级类型操作中更灵活、更“透明”。


✅ 3. 更好的 Tree-shaking 支持

  • 因为它是普通对象导出,现代打包工具(如 Vite、Webpack、Rollup)可以轻松进行 tree-shaking。
  • enum 是一个封闭作用域内的变量声明,难以被 tree-shaken,即使你只用其中一个值,整个 enum 可能都会被打包进去。

✅ 4. 避免 enum 的陷阱

  • enum 允许动态访问(如 IntroduceShopSteps[someString]),可能返回 undefined 或意外值,破坏类型安全
  • as const 对象配合类型系统,强制你在使用前做合法性检查(除非显式放宽类型)。

✅ 5. 与现代 TS/JS 生态更契合

  • 许多库(如 React、Redux Toolkit、Zod 等)都采用这种“const object + union type”模式。
  • 它天然支持 ESM 按需导入模块解析清晰,也更容易与 JSON Schema、OpenAPI 等外部系统对接(因为值就是字符串)。

⚠️ 小缺点(权衡)

  • 不能像 enum 那样直接用 IntroduceShopSteps.CUSTOMIZE_SHOP 作为类型(但你可以用 typeof IntroduceShopSteps.CUSTOMIZE_SHOP)。
  • 书写略冗长(需要手动写类型提取那一行),但可通过工具或模板缓解。

总结

| 特性 | as const 对象 | enum |
|------|------------------|--------|
| 运行时体积 | 极小(原生对象) | 较大(双向映射) |
| 类型精度 | 高(字面量联合) | 高 |
| Tree-shaking | ✅ 支持 | ❌ 难以支持 |
| 可读性/习惯 | 更贴近 JS | TS 特有语法 |
| 安全性 | 更严格(无隐式动态访问) | 可能意外访问无效 key |

因此,在大多数现代 TypeScript 项目中(尤其是前端),推荐使用 as const + 类型提取的方式替代 string enum。这也是社区(如 ESLint、React 团队)逐渐推崇的做法。

如果你追求极致的类型安全、包体积和可维护性,你的写法是更优选择