# enum-plus **Repository Path**: mirrors/enum-plus ## Basic Information - **Project Name**: enum-plus - **Description**: 和原生 enum 一样,但更强大! 简介 enum-plus是一个增强版的枚举类库,完全兼容原生enum的基本用法,同时支持扩展显示文本、绑定到 UI 组件以及提供丰富的扩展方法, - **Primary Language**: TypeScript - **License**: MIT - **Default Branch**: master - **Homepage**: https://www.oschina.net/p/enum-plus - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 2 - **Created**: 2025-04-16 - **Last Updated**: 2025-12-13 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README [English](./README.md) | [中文](./README.zh-CN.md) | [CHANGELOG](./CHANGELOG.md)

enum-plus

像原生 enum 一样,但更强大!


[![npm latest version](https://img.shields.io/npm/v/enum-plus.svg?cacheSeconds=86400)](https://www.npmjs.com/package/enum-plus) [![npm package minimized gzipped size](https://img.shields.io/bundlejs/size/enum-plus?logo=javascript&label=Minzipped&color=44cc11&cacheSeconds=86400)](https://www.npmjs.com/package/enum-plus?activeTab=code) [![npm downloads](https://img.shields.io/npm/dm/enum-plus.svg?logo=rolldown&logoColor=fd7b24&label=Downloads&color=007ec6&cacheSeconds=86400)](https://www.npmjs.com/package/enum-plus) [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/shijistar/enum-plus) [![code coverage](https://codecov.io/gh/shijistar/enum-plus/graph/badge.svg?token=JMCDJKLT0B)](https://app.codecov.io/gh/shijistar/enum-plus) ![GitHub License](https://img.shields.io/github/license/shijistar/enum-plus?label=License&color=ff8000&cacheSeconds=86400) **支持平台** [![Node compatibility](https://img.shields.io/node/v/enum-plus?logo=nodedotjs&label=Node.js&color=2185D0&cacheSeconds=86400)](https://github.com/shijistar/enum-plus) [![Web Browsers](https://img.shields.io/badge/Web%20Browser-2185D0?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAABa1BMVEUAAAD/1kZap04co1BLr1H/1kZKr0//zDbmXC6IzZv95Y390jpLr09Lr0//1kT/1kU8rE/aeibNi13NfUz3kUrDjVrZaTjZWib2YSn2YSj3iC33xRp7q1/91kX9211cuWxBsWv81VL/10f1jhX411Uqpk771Ub2byLNazVTq0xAq09Lr0/91EBAqk6SwFkipFD8zi/GZiz1dSHGYCb2dSDKykirw0oup0/6yiO2dzn2fhuzdDVKrlD1fxv1gBtHrU+hcCr4wRT3Vi1Lr1D/1kVHr1D+1T//10b3Uyr3TyUel+wWj+f2hhn6yiT3SR74wxOn2PmdzfINh+FErVA8rFAxqFD90Tf8zjD2Ow3j8/7g7/sinO8Zk+kRi+QIgt73RBin1fYto/EMgt3J58z88MLYvJxBrVA5qlAqplAkpFD0WC33QBOu3Pvf7vre7vqgzfG748v97rtRqk1knUSBiDembSftUiTFWBrhRxFiNA5aAAAAQnRSTlMAUQX89dtVBfv6+fHapqSJUQ39/f38/Pz7+/j48/Py8fHx7+7s6+fj4t7d3NjX1dXRz8/OzsHApqWTk46MiomAfUvELz/2AAABGUlEQVQoz52P11rCQBBGQ4mhKIK999577ytKEo2JgiaxgAIWsPfHd3Z2JXDLuTzn+ydZoWwiy0O+XK55cCVS6ld9sR1G03qRdk/LcgwKY8YJs5qGgTP377fMpCYXlw1+aPg3T0tDTV3LAdIrYaggn2Ze+85aum69tR5RtjFUEfJjJrOP1+eKksocUpYwVBLyYTZa4C9U1e4+A6YweAkhX7U69ZfHRuAUCBbCe72O/soI7AFBfgposxXqb547aBjjH6ekUyr4l8wuJcR/F4h607ZhPL32YXCxB46Cj57cdvr9XRPoRUlgEwzxu8SDZ4APOGt0EE/cexbQVwsFNtmgv30fAO8QHqGDedAi3nFwhxcnx3vEkEsSyuUPnANWVoDZ/WEAAAAASUVORK5CYII=)](https://www.npmjs.com/package/enum-plus) [![React Native](https://img.shields.io/badge/ReactNative-2185D0?logo=react)](https://reactnative.dev) [![MiniProgram](https://img.shields.io/badge/MiniProgram-2185D0?logo=wechat)](https://developers.weixin.qq.com/miniprogram/dev/framework) [![Taro](https://img.shields.io/badge/Taro-18BCF2?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACkAAAAcCAMAAADLCWbaAAABSlBMVEUAAAAAL7MAJ7QAKrcAJ7NxyP90zP8Pev8Tfv8Tff8Uff8Rff9zyv8Tgv8AT9hzy/8Uf/9zyv8Uff8TfP8AJ7Ryyv8AJ7UVff8AJ7IUfv8Tfv8AJrVzyf8Sff8Te/8Vfv8DKbsTev8Mef8Maextv/8AM60AKLZ1zP8Vfv8AKbQAJ7Rvxv8AKLRuxP8AJ7R0y/8MXuIFQ8tzy/8AKLR0y/8BLbkUfv8AJ7Ryyf90yf9Hpv9zyf8Vff8AJrQPbPFyyv9zyv9zy/8AJ7RGo/8Sfv8AKbFivv8Se/9wzP8AI65t2/8Ufv8AKLR0yv8AKbgWg/93zv92zf91y/8WhP8Xgf9ivP8ojv8UgP8AJrMWhf8FP8hMrP8UffwJUtoDNsEBLrx30P9txP9kvv9atf9Tr/89nv8qjv8kiv8Whv8Sd/gRbvEOZegMXOIIStE2vhD3AAAAS3RSTlMACeQkszTNDH24nYFbFgTv7uTb1dXMmF9UTUVDPTcvKSkiHhMODPr59vXx7uzd3djSysPBwL28t66rpqCTk4SCfHZwZlU+Jx0ZFgduc4qrAAABVElEQVQ4y42QV1PCQBCAo4ihF+m923vvvQu5BIIxIGDv/v9Xb+9B9jJzjt/j3jf37awkxhOs1/osstmAhYoPpstqDbEPo5PwIM90nE7Tc5xphx+XlCqHMpGi4wM/jgclysVo1WKGbXS8oSGzvgVmXLGYvZWSLJ9GcFzzUNEX5U2l1Zl3uN2bUxoyx85hzVlOvGm9E9IgRruG4xGI5y3xb3IFPGo4vgfmIf9l70sH8aWJTTUN5hpvdj+Y+XyP4/4yFSuTljVvWfxJ1QCVcbd+Sc2U5ZYdtqbefmgCM8MMD8R3FI7up87M12vGkZ1RBjM6xLFA478YoaLUx8aR320gk2yXJBFeF0GmeSwJyY4YyAxkxWaCizvPhKLsxqbpkIVmYRWvqSfF8cw4FkM5oeiLmXhNl/efN3qLieM5fCMjkBGbSf5GBfGNHNhs/HGjopPgPxP86w8TLLu5GsqeugAAAABJRU5ErkJggg==)](https://taro.zone/) ⬇️  [简介](#简介) | [特性](#特性) | [安装](#安装) | [枚举定义](#枚举定义) | [API](#api) | [静态方法](#静态方法) | [全局配置](#全局配置) | [使用案例](#使用案例) | [插件系统](#插件系统) | [本地化](#本地化) | [全局扩展](#全局扩展) | [命名冲突](#命名冲突) | [最佳实践](#最佳实践)| [兼容性](#兼容性) | [常见问题](#常见问题) | [支持](#支持)  ⬇️ > **🎉 v3.0 发布了!** > > 新版本是一个重大的里程碑版本,带来了很多令人兴奋的功能和改进,详情请参考 [发布说明](./docs/release-v3.zh-CN.md) 和 [迁移指南](./docs/migration-guide-v2-to-v3.zh-CN.md)。 > > 如果升级后,你遇到枚举类型都变成 `any` 的问题,请看[这里](#为什么升级到-30-之后所有枚举的类型都变成了-any)。 ## 简介 `enum-plus` 是一个增强版的枚举类库,完全兼容原生`enum`的用法,是原生枚举的直接替代品。支持为枚举项添加显示名称,以及添加自定义元数据字段。可以用枚举直接生成下拉框、多选框、菜单、选项卡等各种 UI 控件,对前端工程师非常实用。 为枚举增加了很多扩展方法,支持对枚举项数组的遍历和各种数据转换。你可以把数值转换为多种语言的枚举名称,因为它支持国际化,这在 UI 回显业务数据时非常有用。 这是一个轻量级、零依赖、100% TypeScript 实现的工具库,适用于任何前端框架,包括无框架的纯原生应用。 还有哪些令人兴奋的特性呢?请继续探索吧!或者不妨先看下这个使用视频。

usage video

这里有几个常见问题,有兴趣也可以阅读一下 - [为什么需要这个库?TypeScript 已经有内置的枚举了](#为什么需要这个库typescript-已经有内置的枚举了) - [我必须使用 TypeScript 吗?我的是 JavaScript 项目要怎么办?](#我必须使用-typescript-吗我的是-javascript-项目要怎么办) - [枚举库的性能怎么样?](#枚举库的性能怎么样) - [好像 TypeScript 要废弃 enum 了?](#好像-typescript-要废弃-enum-了) - [我有一个很好的点子,希望为这个项目做贡献,我要怎么做?](#我有一个很好的点子希望为这个项目做贡献我要怎么做)
## 特性 - 完全兼容原生 `enum` 的用法 - 支持`number`、`string`等多种数据类型 - 枚举项支持设置显示名称 - 支持国际化,可与任何 i18n 库集成 - 快速将值转换为显示名称,在 UI 回显时非常有用 - 枚举项支持扩展元数据字段,可以作为静态配置系统使用 - 支持插件体系,可以通过安装插件扩展枚举功能 - 支持数据类型约束,提高代码的类型安全性_  TypeScript_ - 枚举可以生成下拉框等 UI 组件,支持 [Ant Design](https://ant-design.antgroup.com/components/overview-cn)、[Element Plus](https://element-plus.org/zh-CN/component/select.html)、[Material-UI](https://mui.com/material-ui) 等多种组件库 - 支持 Web浏览器、Node.js、React Native、Taro、小程序等多种环境 - 支持服务端渲染 (SSR) - 兼容任何前端开发框架,支持无框架的纯原生项目 - 面向 TypeScript 设计,具有良好的类型推导和代码补全能力 - 零依赖项 - 轻量(gzip压缩后仅2KB+) ## 安装 使用 npm 安装: ```bash npm install enum-plus ``` 使用 pnpm 安装: ```bash pnpm add enum-plus ``` 使用 bun 安装: ```bash bun add enum-plus ``` 或者使用 yarn: ```bash yarn add enum-plus ``` **浏览器中运行**: - 特定版本号: ```html ``` - 最新版本: ```html ``` ⬇️ **下载文件**: - [enum-plus.umd.min.js.gz](https://github.com/shijistar/enum-plus/releases/download/v3.1.6/enum-plus.umd.min.js.gz) - [enum-plus.umd.tar.gz](https://github.com/shijistar/enum-plus/releases/download/v3.1.6/enum-plus.umd.tar.gz) (含 sourcemap) - [enum-plus-legacy.umd.min.js.gz](https://github.com/shijistar/enum-plus/releases/download/v3.1.6/enum-plus-legacy.umd.min.js.gz) - [enum-plus-legacy.umd.tar.gz](https://github.com/shijistar/enum-plus/releases/download/v3.1.6/enum-plus-legacy.umd.tar.gz) (含 sourcemap) > 你也可以从 [GitHub 发布](https://github.com/shijistar/enum-plus/releases/tag/v3.0.1) 下载这些文件 ## 枚举定义 本节展示了使用 `Enum` 函数初始化枚举的多种方式,你可以根据不同的使用场景选择最合适的方法 ### 1. Key-Value 格式 ```js import { Enum } from 'enum-plus'; // Number 类型 const WeekEnum = Enum({ Sunday: 0, Monday: 1, }); WeekEnum.Monday; // 1 // String 类型 const WeekEnum2 = Enum({ Sunday: 'Sun', Monday: 'Mon', }); WeekEnum2.Monday; // 'Mon' ``` > 如果你的项目使用 TypeScript 且版本低于 5.0,那么建议你为 Enum 方法的参数添加 `as const` 类型断言,这样枚举值将保持原始的字面量值,而不会变成`number`、`string`类型。关于更多详情,请参考 [这里](#typescript-版本必须升级到-50-吗)。 ### 2. 标准格式(推荐) 为每个枚举项指定 `value` (枚举值) 和 `label`(显示名称)字段,这是最常用的格式,也是推荐的格式。这种格式允许你为每个枚举项设置显示名称,这些文本可以在 UI 组件中使用。关于为 `label` 字段启用本地化支持,请参考[本地化](#本地化)章节 ```js import { Enum } from 'enum-plus'; const WeekEnum = Enum({ Sunday: { value: 0, label: '星期日' }, Monday: { value: 1, label: '星期一' }, }); WeekEnum.Sunday; // 0 WeekEnum.items[0].key; // 'Sunday' WeekEnum.items[0].label; // 星期日 ``` > 想要输入 `label` 时启用代码智能提示?请参考 [启用枚举项标签的智能提示](#-启用枚举项标签的智能提示) 章节,了解更多详情。 > > 希望自定义 `label` 字段逻辑?可以传入一个函数,请参考 [自定义 label 逻辑](#自定义-label-逻辑) 章节,了解更多详情。 ### 3. Key-Label 格式 只提供 `key` 和 `label` 字段创建枚举。如果省略了 `value` 字段,则它默认为与 `key` 字段相同。 ```js import { Enum } from 'enum-plus'; const WeekEnum = Enum({ Sunday: { label: '星期日' }, Monday: { label: '星期一' }, }); WeekEnum.Sunday; // 'Sunday' WeekEnum.items[0].key; // 'Sunday' WeekEnum.items[0].label; // 星期日 ``` ### 4. 数组格式 数组格式在需要动态创建枚举时很有用,例如从 API 获取数据中动态创建一个枚举。 你可以动态映射字段以适应各种不同的数据结构。请参考 [数组格式初始化,设置不同的字段映射](#-在数组初始化方式中设置不同的字段映射) 章节,了解更多详情。 ```js import { Enum } from 'enum-plus'; const pets = [ { value: 1, key: 'Dog', label: '可爱的小狗' }, { value: 2, key: 'Cat', label: '萌萌的小猫' }, { value: 3, key: 'Rabbit', label: '白白的小兔' }, ]; const PetEnum = Enum(pets); PetEnum.Dog; // 1 PetEnum.label(1); // 狗 ``` ### 5. 原生枚举格式 如果你已经有一个原生的枚举,你可以直接传递给`Enum`函数,它会自动转换为增强版的枚举,这样可以借用原生枚举的`枚举值自动递增`特性 ```ts import { Enum } from 'enum-plus'; enum WeekNative { Sunday = 0, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, } const WeekEnum = Enum(WeekNative); WeekEnum.Sunday; // 0 WeekEnum.Monday; // 1 WeekEnum.Saturday; // 6 ``` > 请注意:当创建枚举对象时,所有枚举项的数据结构必须保持一致。例如,不能在同一个枚举中同时使用 Key-Value 格式和标准格式。 > > 枚举还支持一些配置项,以更好地控制枚举的行为,详情请参考 [枚举配置选项](#-枚举配置选项) 章节。 ## API ### 💎   拾取枚举值 `Enum.XXX` 像原生`enum`一样,直接拾取一个枚举值 ```js WeekEnum.Sunday; // 0 WeekEnum.Monday; // 1 ``` --- ### 💎   named `Record` 一个聚合了所有枚举项的只读对象,可以通过`key`来快速访问某个枚举项对象。 ```js WeekEnum.named.Monday; // { key: 'Monday', value: 1, label: '星期一' } ``` ### 💎   items `{ value, label, key, raw }[]` 获取一个包含全部枚举项的只读数组,可以方便地遍历枚举项。 ```js WeekEnum.items; // [ { value: 0, label: '星期日', key: 'Sunday' }, { value: 1, label: '星期一', key: 'Monday' }, ... ] ``` --- ### 💎   values `(string | number)[]` 获取一个包含全部枚举项`value`的数组 ```js WeekEnum.values; // [0, 1, 2, 3, 4, 5, 6] ``` --- ### 💎   labels `string[]` 获取一个包含全部枚举项`label`的数组 ```js WeekEnum.labels; // ['星期日', '星期一', ... '星期五', '星期六'] ``` --- ### 💎   keys `string[]` 获取一个包含全部枚举项`key`的数组 ```js WeekEnum.keys; // ['Sunday', 'Monday', ... 'Friday', 'Saturday'] ``` --- ### 💎   meta `Record` 获取一个包含全部枚举项自定义字段的聚合对象,键是字段名,值是该字段的所有枚举项值的数组,这样可以在不遍历枚举项的情况下访问自定义字段。 ```js const ColorEnum = Enum({ Red: { value: 1, label: '红色', hex: '#FF0000' }, Green: { value: 2, label: '绿色', hex: '#00FF00' }, Blue: { value: 3, label: '蓝色', hex: '#0000FF' }, }); ColorEnum.meta.hex; // ['#FF0000', '#00FF00', '#0000FF'] ``` 顺便一提,你可以通过 `named` 和 `raw` 属性快速访问单个枚举项的自定义字段 ```js ColorEnum.named.Red.raw.hex; // '#FF0000' ``` --- ### 💎   has **_\[方法]_**   `has(keyOrValue?: string | number): boolean` 判断某个枚举项(值或 key)是否存在 ```js WeekEnum.has(1); // true WeekEnum.has('Sunday'); // true WeekEnum.has(9); // false WeekEnum.has('Birthday'); // false ``` --- ### 💎   findBy **_\[方法]_**   `findBy(field: string, value: any): EnumItemClass | undefined` 根据指定字段和字段值,获取枚举项对象,如果不存在则返回`undefined` 字段名支持:`key`、`value`、`label`或元数据字段 ```js ColorEnum.findBy('value', 1); // { key: 'Red', value: 1, label: '红色', hex: '#FF0000' } ColorEnum.findBy('key', 'Red'); // { key: 'Red', value: 1, label: '红色', hex: '#FF0000' } ColorEnum.findBy('hex', '#FF0000'); // { key: 'Red', value: 1, label: '红色', hex: '#FF0000' } ``` --- ### 💎   label **_\[方法]_**   `label(keyOrValue?: string | number): string | undefined` 根据某个枚举值或枚举 key,获取该枚举项的显示名称。如果启用了[本地化](#本地化),则会返回当前语言的内容。 ```js WeekEnum.label(1); // 星期一 WeekEnum.label('Monday'); // 星期一 ``` --- ### 💎   key **_\[方法]_**   `key(value?: string | number): string | undefined` 根据枚举值获取该枚举项的`key`,这也被称为[反向映射](https://www.typescriptlang.org/docs/handbook/enums.html#reverse-mappings)。如果不存在则返回`undefined` ```js WeekEnum.key(1); // 'Monday' ``` --- ### 💎   raw **_\[方法^1]_**   `raw(): Record`
**_\[方法^2]_**   `raw(keyOrValue: V | K): T[K]` `raw`方法有两种重载形式。第一种是返回整个枚举集合的原始初始化对象,即`Enum`方法的第一个参数。 第二种是返回单个枚举项的原始初始化对象,即`Enum`方法的第一个参数中对应字段的子对象。 这个方法主要作用是,用来获取枚举项的自定义字段。 ```js const WeekEnum = Enum({ Sunday: { value: 0, label: '星期日', happy: true }, Monday: { value: 1, label: '星期一', happy: false }, }); WeekEnum.raw(0).happy; // true WeekEnum.raw(0); // { value: 0, label: '星期日', happy: true } WeekEnum.raw('Monday'); // { value: 1, label: '星期一', happy: false } WeekEnum.raw(); // { Sunday: { value: 0, label: '星期日', happy: true }, Monday: { value: 1, label: '星期一', happy: false } } ``` > 温馨提示:如果要获取某个已知枚举项的元数据字段,使用`enum.named.XXX.raw` 是一个不错的选择。 --- ### 💎   toList **_\[方法^1]_**   `toList(): { value, label }[]`
**_\[方法^2]_**   `toList(options?: { valueField?: string; labelField?: string }): { [key: string]: any }[]` 将枚举转换为一个默认包含`value`和`label`字段的数组,或者通过`options`参数自定义字段名。 ```js WeekEnum.toList(); // [ // { value: 0, label: '星期日' }, // { value: 1, label: '星期一' }, // ... // { value: 6, label: '星期六' } // ] WeekEnum.toList({ valueField: 'id', labelField: 'name' }); // [ // { id: 0, name: '星期日' }, // { id: 1, name: '星期一' }, // ... // { id: 6, name: '星期六' } // ] ``` --- ### 💎   toMap **_\[方法^1]_**   `toMap(): Record`
**_\[方法^2]_**   `toMap(options?: { keySelector?: string; valueSelector?: string }): Record` 将枚举转换为一个默认以`value`为键,`label`为值的对象,或者通过`options`参数自定义键和值的字段名。 ```js WeekEnum.toMap(); // { // "0": '星期日', // "1": '星期一', // ... // "6": '星期六' // } WeekEnum.toMap({ keySelector: 'key', valueSelector: 'value' }); // { // "Sunday": 0, // "Monday": 1, // ... // "Saturday": 6 // } ``` --- ### 💎   name `string` 整个枚举集合的显示名称。可以在创建枚举时,通过传入一个可选的 `name` 参数来为枚举类型命名。这个名称可以是一个普通字符串,也可以是一个本地化键值,以支持国际化文本。请参考[本地化](#本地化)章节,了解更多详情。 ```js const WeekEnum = Enum( { Sunday: { value: 0, label: '星期日' }, Monday: { value: 1, label: '星期一' }, }, { name: 'i18n.enums.week', // 可以普通字符串或者一个本地化键值 } ); WeekEnum.name; // Week 或 周,取决于当前语言 ``` > 在 UI 组件中,枚举通常用来作为数据源,生成下拉框表单项,或在表格单元格中显示枚举成员文本。而对应的表单项标签或列标题就是枚举类型的名称。通过使用`name`,我们可以集中管理枚举名称,和枚举成员的名称,也更方便使用。 --- ### ⚡️   valueType     **_\[TypeScript Only]_** `value1 | value2 | ...` 在 TypeScript 中,提供了一个包含所有枚举值的联合类型,用于缩小变量或组件属性的数据类型。这种类型替代了像 `number` 或 `string` 这样宽泛的原始类型,使用精确的值集合,防止无效赋值,同时提高代码可读性和编译时类型安全性。 ```ts const weekValue: typeof WeekEnum.valueType = 1; function setToday(day: typeof WeekEnum.valueType) { // ... } const MyComponent = (props: { day: typeof WeekEnum.valueType }) => { // ... }; ``` > 注意,这只是一个 TypeScript 类型,只能用来约束类型。不可在运行时调用,运行时调用会抛出异常。 --- ### ⚡️   keyType     **_\[TypeScript Only]_** `key1 | key2 | ...` 与`valueType`类似,获取一个包含全部枚举 `key` 的联合类型 ```ts type WeekKeys = typeof WeekEnum.keyType; // 'Sunday' | 'Monday' const weekKey: typeof WeekEnum.keyType = 'Monday'; const weekKeys: (typeof WeekEnum.keyType)[] = ['Sunday', 'Monday']; ``` > 注意,这只是一个 TypeScript 类型,只能用来约束类型。不可在运行时调用,运行时调用会抛出异常。 --- ### ⚡️   rawType     **_\[TypeScript Only]_** `{ value: V, label: string, [...] }` 获取初始化整个枚举集合的原始类型,即 `Enum` 函数的第一个参数的类型。 不要与 `raw` 方法混淆,`raw` 方法是一个运行时方法,而`rawType`是一个 TypeScript 的类型。 ```ts type WeekRaw = typeof WeekEnum.rawType; // { Sunday: { value: 0, label: string }, Monday: { value: 1, label: string } } ``` > 注意,这只是一个 TypeScript 类型,只能用来约束类型。不可在运行时调用,运行时调用会抛出异常。 --- ## 静态方法 ### 💎   Enum.isEnum **_\[方法]_**   `isEnum(obj: any): boolean` 判断一个对象是否是一个由`Enum`函数创建的枚举对象 ```js Enum.isEnum(WeekEnum); // true Enum.isEnum({}); // false ``` --- ### 💎   Enum.localize **_\[方法]_**   `(key: string) => string` 设置全局的本地化函数,用来处理枚举类型名称和枚举项显示名称的本地化。请参考 [本地化](#本地化) 章节,了解更多详情。 ```js import i18n from 'i18next'; Enum.localize = (key) => i18n.t(key); ``` --- ### 💎   Enum.extends **_\[方法]_**   `(obj: Record) => void` 为所有枚举对象添加全局扩展方法,请参考[全局扩展](#全局扩展)章节,了解更多详情。 ```js Enum.extends({ sayHello() { return `你好,EnumPlus!`; }, }); ``` --- ### 💎   Enum.install **_\[方法]_**   `(plugin: Plugin, options?: any) => void` 安装一个插件,插件可以为所有枚举添加新的功能。请参考[插件系统](#插件系统)章节,了解更多详情。 ```js import i18nextPlugin from '@enum-plus/plugin-i18next'; Enum.install(i18nextPlugin); ``` ## 全局配置 `Enum.config` 提供了一些全局配置参数,用来影响枚举的行为和特性。 ### autoLabel `Enum.config.autoLabel` 是一个全局配置选项,用于自动生成枚举项的标签。它允许在定义枚举时,设置 `options.labelPrefix` 选项,为所有枚举项设置一个 `label` 前缀,枚举项只需要设置基础值即可,甚至可以省略 `label` 字段(与 `key` 字段相同)。这样可以减少重复代码,提高枚举定义的简洁性。 `Enum.config.autoLabel` 的值可以是一个布尔值,也可以使用 `function` 类型的函数以实现更复杂的逻辑。 - `true` - 默认值,启用自动标签生成功能。枚举项的 `label` 最终值将自动设置为 `labelPrefix`+`label`,如果省略了 `label` 字段,则使用 `labelPrefix`+`key` 规则。当然,如果创建枚举时没有设置 `labelPrefix`,则此选项将没有任何效果。 - `function` - 一个自定义函数,用于自定义每个枚举项 `label` 生成规则。该函数接受一个选项对象参数,其中包含:`item`(枚举项对象)和 `labelPrefix`,并返回一个字符串作为最终的 `label` 值。 ```js Enum.config.autoLabel = ({ item, labelPrefix }) => { return `${labelPrefix}.${item.key.lowerFirst()}`; }; ``` - `false` - 禁用自动标签生成功能,枚举项必须显式提供 `label` 字段。 > 请注意,在创建枚举时也可以通过 `options.autoLabel` 参数覆盖全局配置,其用法与 `Enum.config.autoLabel` 相同。 ## 使用案例 ### 💡 基础用法,消除魔法数字 ```js const WeekEnum = Enum({ Sunday: { value: 0, label: '星期日' }, Monday: { value: 1, label: '星期一' }, }); if (today === WeekEnum.Sunday) { // 今天是星期天,享受你的一天吧! } else if (today === WeekEnum.Monday) { // 哦不,又是星期一了... } ``` --- ### 💡 检查是否一个有效的枚举值 ```js if (WeekEnum.has(value)) { // 是一个有效的枚举值,可以安全使用 } else { // 抛出异常或使用默认值 } ``` --- ### 💡 检查是否一个枚举对象 ```ts let values: number[] | undefined; if (Enum.isEnum(data)) { values = data.values; } else if (Array.isArray(data)) { values = data; } else { // 非法输入,抛出异常或使用默认值 } ``` --- ### 💡 生成 UI 组件 以 React + Ant Design 为例,更多 UI 组件的案例请参考 [支持多种前端框架](#-支持多种前端框架) 章节 ```jsx import { Menu, Select, Table } from 'antd'; import { ProFormCheckbox, ProFormSelect } from '@ant-design/pro-components'; const App = () => { return ( <> ; ``` [Material-UI](https://mui.com/material-ui/react-select/) Select ```tsx import { MenuItem, Select } from '@mui/material'; ; ``` [Kendo UI](https://www.telerik.com/kendo-react-ui/components/dropdowns/dropdownlist) Select ```tsx import { DropDownList } from '@progress/kendo-react-dropdowns'; ; ``` - **Vue相关框架** [Element Plus](https://element-plus.org/zh-CN/component/select.html) Select ```html ``` [Ant Design Vue](https://antdv.com/components/select-cn) | [Arco Design](https://arco.design/vue/component/select) Select ```html ``` [Vuetify](https://vuetifyjs.com/zh-Hans/components/selects) Select ```html ``` - **Angular相关框架** [Angular Material](https://material.angular.io/components/select/overview) Select ```html @for (item of WeekEnum.items; track item.value) { {{ item.label }} } ``` [NG-ZORRO](https://ng.ant.design/components/select/zh) Select ```jsx @for (item of WeekEnum.items; track item.value) { {{ item.label }} } ``` --- ### 💡 枚举配置选项 在创建枚举时,可以传入一个可选的配置对象,用来定制枚举的行为和特性。下面是一些常用的配置选项: ```ts interface EnumOptions { /** 枚举类型名称,可以是一个普通字符串,或者一个本地化键值 */ name?: string; /** 为所有枚举项设置一个标签前缀,更多详情请参考 [全局配置] 章节 */ labelPrefix?: string; /** 自动生成枚举项标签的规则,更多详情请参考 [全局配置] 章节 */ autoLabel?: boolean | ((params: { item: EnumItemClass; labelPrefix?: string }) => string); /** 枚举实例级别的本地化函数,会覆盖 Enum.localize 全局配置函数 */ localize?: (localeKey: string) => string; } ``` 更多配置选项,请参考下面一个章节。 --- ### 💡 在数组初始化方式中,设置不同的字段映射 在 [4. 数组格式](#4-数组格式) 章节中,介绍了可以通过后端动态数据来构建枚举,但是很可能动态数据的字段名并不是`value`、`label`、`key`,而是其它的字段名。这时你可以传入一个自定义选项,把这些映射到其它字段名上 ```js import { Enum } from 'enum-plus'; const data = await getPetsData(); // [ { id: 1, code: 'dog', name: '狗' }, // { id: 2, code: 'cat', name: '猫' }, // { id: 3, code: 'rabbit', name: '兔' } ]; const PetTypeEnum = Enum(data, { getValue: 'id', getLabel: 'name', getKey: 'code', // getKey可选 }); PetTypeEnum.items; // 输出如下: // [ { value: 1, label: '狗', key: 'dog' }, // { value: 2, label: '猫', key: 'cat' }, // { value: 3, label: '兔', key: 'rabbit' } ] ``` 在上面的例子中,`getValue`、`getLabel`、`getKey` 还可以是一个函数,用来处理更复杂的业务逻辑,比如: ```js const PetTypeEnum = Enum(petTypes, { getValue: (item) => item.id, getLabel: (item) => `${item.name} (${item.code})`, getKey: (item) => item.code, }); ``` --- ## 插件系统 `enum-plus` 提供了一个插件系统,允许你为枚举添加额外的功能。插件可以为所有枚举实例添加新的方法或属性,极大地扩展了枚举的功能。你可以选择性地安装需要的插件,而不是将所有功能都打包在一起,从而保持核心库的轻量和高效。 ```ts import antdPlugin from '@enum-plus/plugin-antd'; import { Enum } from 'enum-plus'; Enum.install(antdPlugin); ``` 当你安装一个插件后,插件会为所有枚举实例添加新的方法或属性。例如,安装了 [@enum-plus/plugin-antd](https://github.com/shijistar/enum-plus/tree/master/packages/plugin-antd) 插件后,你可以使用 `enum.toSelect` 方法使用枚举生成一个 Select 组件。 你还可以设置插件的可选配置选项,以定制插件的行为,关于插件的配置选项,请参考各个插件的文档。 ```ts import antdPlugin from '@enum-plus/plugin-antd'; import { Enum } from 'enum-plus'; Enum.install(antdPlugin, { toSelect: { valueField: 'id', // 设置 toSelect 方法生成的数据对象中,关于值的字段名 labelField: 'name', // 设置 toSelect 方法生成的数据对象中,关于枚举名称的字段名 }, }); ``` ### 插件生态 目前我们已经开发并发布了以下插件,你可以根据需要选择安装: - [@enum-plus/plugin-antd](https://github.com/shijistar/enum-plus/tree/master/packages/plugin-antd) 面向 [Ant Design](https://ant-design.antgroup.com) 的功能扩展,包括 `enum.toSelect`、`enum.toMenu`、`enum.toFilter` 和 `enum.toValueMap`。通过这些方法,可以直接将枚举绑定到对应的 Ant Design 组件上,极大地简化了代码。 - [@enum-plus/plugin-i18next](https://github.com/shijistar/enum-plus/tree/master/packages/plugin-i18next) 集成 [i18next](https://www.i18next.com) 并实现枚举标签的国际化。 - [@enum-plus/plugin-react-i18next](https://github.com/shijistar/enum-plus/tree/master/packages/plugin-react-i18next) 自动适配 [react-i18next](https://react.i18next.com) 以让枚举支持国际化。 - [@enum-plus/plugin-react](https://github.com/shijistar/enum-plus/tree/master/packages/plugin-react) React 集成,包括支持 `Enum.localize` 返回 React 组件,以及监听语言变化以自动重新渲染组件。 - [@enum-plus/plugin-i18next-vue](https://github.com/shijistar/enum-plus/tree/master/packages/plugin-i18next-vue) 集成 [i18next-vue](https://github.com/shijistar/enum-plus/tree/master/packages/plugin-i18next-vue) 并实现枚举标签的国际化,支持切换语言后自动更新UI。 - [@enum-plus/plugin-vue-i18n](https://github.com/shijistar/enum-plus/tree/master/packages/plugin-vue-i18n) 集成 [vue-i18n](https://vue-i18n.intlify.dev) 并实现枚举标签的国际化,支持切换语言后自动更新UI。 我们正在开发以下插件: - [@enum-plus/plugin-angular](https://github.com/shijistar/enum-plus/tree/master/packages/plugin-angular): Angular 集成,包括支持 `Enum.localize` 返回 Angular 组件,以及监听语言变化以自动重新渲染组件。_我们需要你的帮助来开发这个插件!_ > 如果你没有找到需要的插件,或者你想开发自己的插件,请参阅 [插件开发指南](./docs/plugin-development.zh-CN.md)。你可以在enum-plus官方仓库中开发新插件,也可以将你开发的插件发布到 npm 上,并把你的插件链接分享在这里。我们真诚地需要你的帮助,来丰富插件生态系统! --- ## 本地化 enum-plus 默认不内置国际化能力,因此枚举项的`label`字段将被视为普通字符串,直接返回原始文本。 为 enum-plus 添加本地化支持,最简单的方式是安装对应的 [i18n插件](#插件生态),例如 `@enum-plus/plugin-i18next`,它会自动将 `label` 和 `name` 字段的值传递给 i18next 进行翻译。 ```bash npm install @enum-plus/plugin-i18next i18next ``` 然后在项目入口文件中安装插件: _index.js_ ```js import i18nextPlugin from '@enum-plus/plugin-i18next'; import { Enum } from 'enum-plus'; Enum.install(i18nextPlugin); ``` 安装了插件后,枚举的 `label` 和 `name` 字段将自动通过 i18next 进行翻译。 ```js const WeekEnum = Enum( { Sunday: { value: 0, label: 'week.sunday' }, Monday: { value: 1, label: 'week.monday' }, }, { name: 'weekDays.name' } ); WeekEnum.label(1); // Monday 或 星期一,取决于当前语言环境 WeekEnum.named.Monday.label; // Monday 或 星期一,取决于当前语言环境 WeekEnum.name; // Week 或 周,取决于当前语言环境 ``` 此插件还支持自定义 i18next 选项,甚至允许完全控制 localize 方法,请参考[插件文档](https://github.com/shijistar/enum-plus/tree/master/packages/plugin-i18next/README.zh-CN.md#插件选项),了解更多详情。 如果你需要切换语言后自动更新UI,这需要借助 React、Vue 或 Angular 等框架的能力,请考虑使用 [@enum-plus/plugin-react](https://github.com/shijistar/enum-plus/tree/master/packages/plugin-react) 或 [@enum-plus/plugin-vue](https://github.com/shijistar/enum-plus/tree/master/packages/plugin-vue) 等插件。 如果你使用的是其它国际化库,例如 `react-intl`、`vue-i18next` 或 `ngx-translate`,你可以通过 `Enum.localize` 方法来集成这些库。 _my-extension.js_ ```js import { Enum } from 'enum-plus'; Enum.localize = (key) => { // 这是一段伪代码,请根据你使用的国际化库进行调整 return intl.formatMessage({ id: key }); }; ``` > 一旦你完成了这项功能,建议你考虑把它发布成一个 npm 包,并分享在[插件生态](#插件生态)章节中,这样其他人也可以受益于你的工作。如果你觉得这个项目非常通用,也可以考虑把它提交到 [enum-plus](https://github.com/shijistar/enum-plus/tree/master/packages) 官方插件库中,具体开发规则请参阅 [插件开发指南](./docs/plugin-development.zh-CN.md)。 ### 自定义 label 逻辑 当然,如果不使用任何国际化框架,而是希望自己控制枚举 `label` 的本地化规则,或者为每个枚举项使用不同的自定义逻辑,你可以为 `label` 字段传入一个函数: ```js const WeekEnum = Enum({ Sunday: { value: 0, label: () => '星期日' }, Monday: { value: 1, label: () => '星期一' }, }); ``` 另外,enum\.name 也支持使用自定义函数。 ````js const WeekEnum = Enum( { //... }, { name: () => '周', } ); ``` --- ## 全局扩展 Enum 提供了丰富的内置方法和属性,它们已经可以满足大多数常见的使用场景。如果这些还不够,你还可以使用 `Enum.extends` 扩展更多的自定义方法。这些扩展会全局应用于所有枚举实例,包括在扩展应用之前创建的实例,并且会立即生效,无需任何额外的设置。 > 实际上,整个[插件系统](#插件系统)以及 `Enum.install` 在底层都是通过 `Enum.extends` 来实现的。 - **TypeScript 项目** _my-enum-extension.ts_ ```ts // 功能实现 Enum.extends({ toMySelect() { return this.items.map((item) => ({ value: item.value, title: item.label })); }, reversedItems() { return this.items.toReversed(); }, }); // 类型声明,以获得更好的类型提示 declare module 'enum-plus/extension' { export interface EnumExtension { toMySelect: () => { value: V; title: string }[]; reversedItems: () => EnumItemClass, K, V>[]; } } ```` _index.ts_ 然后在项目的入口文件中导入这个文件: ```ts import './my-enum-extension'; WeekEnum.toMySelect(); // [{ value: 0, title: '星期日' }, { value: 1, title: '星期一' }] ``` - **JavaScript 项目** _my-enum-extension.js_ ```js import { Enum } from 'enum-plus'; Enum.extends({ toMySelect() { return this.items.map((item) => ({ value: item.value, title: item.label })); }, reversedItems() { return this.items.toReversed(); }, }); ``` _my-enum-extension.js.d.ts_ ```ts import { EnumExtension, EnumItemClass, EnumItemInit } from 'enum-plus'; declare module 'enum-plus/extension' { export interface EnumExtension { toMySelect: () => { value: V; title: string }[]; reversedItems: () => EnumItemClass, K, V>[]; } } ``` _index.js_ 然后在项目的入口文件中导入这个文件: ```js import './my-enum-extension'; WeekEnum.toMySelect(); // [{ value: 0, title: '星期日' }, { value: 1, title: '星期一' }] ``` 注意,`EnumExtension` 是一个泛型接口,它接受三个类型参数,它们的含义分别是: - `T`: 表示枚举类型的初始化对象 - `K`: 表示枚举项的键值 - `V`: 表示枚举项的值 > 如果你希望在扩展方法中提供更友好的类型提示,你可能需要使用到这些类型参数。当然,这些类型参数是可选的,如果你不需要,可以直接忽略掉它们。 --- ## 命名冲突? `enum-plus` 设计时充分考虑了命名冲突的可能性。枚举项的命名空间与枚举实例的方法和属性是分开的,这样可以最大限度地减少冲突的可能性。例如,当枚举项的名称与某个方法名称相同时,你可以通过 `items` 属性访问那些被覆盖的方法。 ```js import { KEYS, VALUES } from 'enum-plus'; const WeekEnum = Enum({ foo: { value: 1 }, bar: { value: 2 }, keys: { value: 3 }, // 命名冲突 values: { value: 4 }, // 命名冲突 label: { value: 5 }, // 命名冲突 named: { value: 6 }, // 命名冲突 toList: { value: 7 }, // 命名冲突 }); WeekEnum.foo; // 1 WeekEnum.bar; // 2 // 以下均为枚举项,优先级更高,会覆盖掉原来的方法 WeekEnum.keys; // 3 WeekEnum.values; // 4 WeekEnum.label; // 5 WeekEnum.named; // 6 WeekEnum.toList; // 7 // 可以 .items 访问到这些被覆盖的方法 🙂 WeekEnum.items[KEYS]; // ['foo', 'bar', 'keys', 'values', 'label', 'named', 'toList'] WeekEnum.items[VALUES]; // [1, 2, 3, 4, 5, 6, 7] WeekEnum.items.label(1); // 'foo' WeekEnum.items.named.foo; // { value: 1, label: 'foo', key: 'foo' } WeekEnum.items.toList(); // [{ value: 1, label: 'foo' }, ...] ``` > 请注意,`keys` 和 `values` 这两个属性比较特殊,因为它们是 JavaScript 数组的内置方法,为了避免改变 items 数组的行为,需要使用 `KEYS` 和 `VALUES` 两个符号作为别名来访问它们。 再极端一点,万一 `items` 与枚举项命名冲突怎么办?放心,你仍然可以通过 `ITEMS` 别名来访问它。 ```js import { ITEMS } from 'enum-plus'; const WeekEnum = Enum({ foo: { value: 1 }, bar: { value: 2 }, items: { value: 3 }, // 命名冲突 toList: { value: 4 }, // 命名冲突 }); WeekEnum.items; // 3,枚举项优先级更高,会覆盖掉 items WeekEnum[ITEMS].toList(); // 但可以通过 ITEMS 别名来访问它 ``` --- ## 最佳实践 在使用 `enum-plus` 创建和管理枚举时,遵循一些最佳实践可以帮助你编写更清晰、可维护的代码。以下是一些建议: 1. **枚举类型命名:** 采用 `PascalCase` 大驼峰命名法,并以 `Enum` 作为后缀,如 _WeekEnum_、_ColorEnum_ 等。 2. **枚举成员命名:** 使用 `PascalCase` 大驼峰命名法,如 _Sunday_、_Red_ 等。这种命名方式突显了枚举成员的静态与不可变性,并且在IDE智能提示中可以显示在顶部,而不是与其它方法名混在一起,更方便查看和拾取。 3. **语义明确:** 确保枚举和成员名称具有清晰的语义,良好的语义命名能够自解释代码意图,降低理解成本。 4. **单一职责原则:** 每个枚举类型应专注表达一组高内聚的相关常量,避免不同枚举类型之间的职责重叠。 5. **提供JSDoc注释:** 为每个枚举项添加 JSDoc 注释,说明其含义和用途。完善的JSDoc文档能在IDE中提供悬停提示,提升代码阅读体验。同样也建议为枚举类添加注释。 6. **国际化架构:** 建议从开始就搭建国际化架构,可集成本库提供的 [本地化](#本地化) 机制。预先设计的国际化方案能够避免后期重构的高成本,并使应用更易于扩展到全球市场。 下面是一个示例,展示了如何结合上述最佳实践来定义一个枚举: ```js /** 表示一周的枚举 */ const WeekEnum = Enum( { /** 星期日 */ Sunday: { value: 0, label: 'enums.week.sunday' }, /** 星期一 */ Monday: { value: 1, label: 'enums.week.monday' }, // ... /** 星期五 */ Friday: { value: 5, label: 'enums.week.friday' }, /** 星期六 */ Saturday: { value: 6, label: 'enums.week.saturday' }, }, { name: 'enums.week.name' } ); ``` --- ## 兼容性 enum-plus 设计之初就考虑了广泛的兼容性需求,可无缝运行于各类环境,包括现代浏览器、Node.js 以及多种构建工具。下面详细说明各环境的兼容性情况: ### 浏览器环境 - **现代打包工具**:对于支持 [exports](https://nodejs.org/api/packages.html#exports-sugar) 配置的打包工具(如 webpack 5+、vite、rollup),代码引入的是 `es` 目录,对应的 ECMAScript 版本是 **`ES2020`**。 - **旧版打包工具**:对于不支持 [exports](https://nodejs.org/api/packages.html#exports-sugar) 配置的旧版打包工具(如 webpack 4),代码引入的是 `es-legacy` 目录,对应的 ECMAScript 版本是 **`ES2015`**。 - **UMD版本**:为了方便在浏览器中直接使用,或者在没有打包工具的静态项目中使用,enum-plus 还提供了 UMD 版本,存放在 `umd` 目录下。UMD 格式的文件可以通过 `