ts-enum-next 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 ricoNext
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,89 @@
1
+ # ts-enum-next
2
+
3
+ <b>English | <a href="./README.zh-CN.md">中文</a></b>
4
+
5
+ - The ultimate solution for next-generation enumeration in TypeScript
6
+
7
+ - Define and use enum in typescript like using enum in java.
8
+
9
+ ## Why?
10
+
11
+ It is very convenient to use enum to define numeric enums and string enums in typescript, but when you are defining some enums of numeric dictionary types, you are a little overwhelmed. For example, when we define a set of states, we need to define the name of the state at the same time. We can combine enumerations and mapping objects in typescript to implement it.
12
+
13
+ ```ts
14
+ enum Status {
15
+ PENDING = 0,
16
+ APPROVED = 1,
17
+ REJECTED = 2
18
+ }
19
+
20
+ const StatusDescriptions = {
21
+ [Status.PENDING]: "waiting",
22
+ [Status.APPROVED]: "Approved",
23
+ [Status.REJECTED]: "reject"
24
+ };
25
+
26
+ console.log(Status.PENDING); // 0
27
+ console.log(StatusDescriptions[Status.PENDING]); // "waiting"
28
+ ```
29
+
30
+ In simple projects, maintaining a "data dictionary" is a good way to do this, but in complex projects, we may need to maintain a large number of "data dictionaries", and these "data dictionaries" may require some inheritance of some "dictionaries" to generate new "dictionaries", or in the business we display different colors for different descriptions in a set of enum values ​​or perform different methods. At this time, the native enum of typescript begins to appear unsatisfied.
31
+
32
+ ts-enum-next According to the definition and use of enum in java, an enum definition and use paradigm similar to java is provided. You can implement Class-based enum definition and use.
33
+
34
+ ## How to use?
35
+
36
+ ### install
37
+
38
+ ```bash
39
+ pnpm add ts-enum-next
40
+ ```
41
+
42
+ ### Define data dictionary
43
+ ```ts
44
+ class HttpStatus extends Enum<number> {
45
+ static readonly OK = new HttpStatus(200, 'OK', 'Request succeeded');
46
+ static readonly BAD_REQUEST = new HttpStatus(400, 'BAD_REQUEST', 'Error request');
47
+ static readonly NOT_FOUND = new HttpStatus(404, 'NOT_FOUND');
48
+ }
49
+ ```
50
+
51
+ ### Using a data dictionary
52
+
53
+ * Get dictionary items
54
+
55
+ ```ts
56
+ console.log(HttpStatus.OK.description); // "Request succeeded"
57
+ console.log(HttpStatus.fromValue(404).name); // "NOT_FOUND"
58
+ console.log(HttpStatus.fromName("BAD_REQUEST").value); // 400
59
+ ```
60
+
61
+ * Get all enum values
62
+
63
+ ```ts
64
+ const allStatuses = HttpStatus.values();
65
+ console.log(allStatuses.map(s => s.name)); // ["OK", "BAD_REQUEST", "NOT_FOUND"]
66
+ ```
67
+
68
+ * Using enumeration collection
69
+
70
+ ```ts
71
+ const errorStatuses = HttpStatus.setOf(
72
+ HttpStatus.BAD_REQUEST,
73
+ HttpStatus.NOT_FOUND
74
+ );
75
+ console.log(errorStatuses.has(HttpStatus.fromValue(400))); // true
76
+ ```
77
+
78
+ * Using enumeration map
79
+
80
+ ```ts
81
+ const statusMessages = HttpStatus.enumMap({
82
+ [HttpStatus.OK.value]: "Operation is successful",
83
+ [HttpStatus.BAD_REQUEST.value]: "Request error",
84
+ "NOT_FOUND": "The resource does not exist"
85
+ });
86
+ console.log(statusMessages.get(HttpStatus.NOT_FOUND)); // "The resource does not exist"
87
+ ``
88
+
89
+
@@ -0,0 +1,91 @@
1
+ # ts-enum-next
2
+
3
+ <b>English | <a href="./README.zh-CN.md">中文</a></b>
4
+
5
+ - TypeScript 中下一代枚举的终极解决方案
6
+
7
+ - 像在 java 中使用 enum 一样,在 typescript 中定义和使用 enum。
8
+
9
+ ## 为什么?
10
+
11
+ 在 typescript 中使用 enum 来定义数字枚举和字符串枚举是非常方便的, 但是在面对一些数字字典类型的枚举做定义时就有点力不从心, 比如我们定义一组状态时需要同时定义状态的名称, 我们可以就需要结合 typescript 中的枚举和映射对象来实现
12
+
13
+ ```ts
14
+ enum Status {
15
+ PENDING = 0,
16
+ APPROVED = 1,
17
+ REJECTED = 2
18
+ }
19
+
20
+ const StatusDescriptions = {
21
+ [Status.PENDING]: "等待处理",
22
+ [Status.APPROVED]: "已批准",
23
+ [Status.REJECTED]: "已拒绝"
24
+ };
25
+
26
+ // 使用示例
27
+ console.log(Status.PENDING); // 0
28
+ console.log(StatusDescriptions[Status.PENDING]); // "等待处理"
29
+ ```
30
+
31
+ 在简单的项目中,这样维护“数据字典”是一个不错的方法, 但是在复杂的项目中,我们可能会需要维护大量的“数据字典”, 并且这些“数据字典” 可能需要一些继承一些“字典” 生成新的“字典”,或者业务中我们对一组枚举值中的不同描述展示不同的颜色或者执行不同的方法,这时 typescript 原生的 enum 就开始显得力不从心了
32
+
33
+ ts-enum-next 根据 java 中对于 enum 的定义和使用,提供了一套类似于 java 的 enum 定义和使用范式, 你可以实现基于 Class 的枚举定义和使用。
34
+
35
+
36
+ ## 使用
37
+
38
+ ### 安装
39
+
40
+ ```bash
41
+ pnpm add ts-enum-next
42
+ ```
43
+
44
+ ### 定义数据字典
45
+ ```ts
46
+ class HttpStatus extends Enum<number> {
47
+ static readonly OK = new HttpStatus(200, 'OK', '请求成功');
48
+ static readonly BAD_REQUEST = new HttpStatus(400, 'BAD_REQUEST', '错误请求');
49
+ static readonly NOT_FOUND = new HttpStatus(404, 'NOT_FOUND');
50
+ }
51
+ ```
52
+
53
+ ### 使用数据字典
54
+
55
+ * 获取字典项
56
+
57
+ ```ts
58
+ console.log(HttpStatus.OK.description); // "请求成功"
59
+ console.log(HttpStatus.fromValue(404).name); // "NOT_FOUND"
60
+ console.log(HttpStatus.fromName("BAD_REQUEST").value); // 400
61
+ ```
62
+
63
+ * 获取所有枚举值
64
+
65
+ ```ts
66
+ const allStatuses = HttpStatus.values();
67
+ console.log(allStatuses.map(s => s.name)); // ["OK", "BAD_REQUEST", "NOT_FOUND"]
68
+ ```
69
+
70
+ * 使用枚举集合
71
+
72
+ ```ts
73
+ const errorStatuses = HttpStatus.setOf(
74
+ HttpStatus.BAD_REQUEST,
75
+ HttpStatus.NOT_FOUND
76
+ );
77
+ console.log(errorStatuses.has(HttpStatus.fromValue(400))); // true
78
+ ```
79
+
80
+ * 使用枚举映射表
81
+
82
+ ```ts
83
+ const statusMessages = HttpStatus.enumMap({
84
+ [HttpStatus.OK.value]: "操作成功",
85
+ [HttpStatus.BAD_REQUEST.value]: "请求错误",
86
+ "NOT_FOUND": "资源不存在" // 支持名称或值作为键
87
+ });
88
+ console.log(statusMessages.get(HttpStatus.NOT_FOUND)); // "资源不存在"
89
+ ``
90
+
91
+
@@ -0,0 +1,19 @@
1
+ type EnumValueType = number | string;
2
+ declare abstract class Enum<T extends EnumValueType> {
3
+ readonly value: T;
4
+ readonly name: string;
5
+ readonly description?: string | undefined;
6
+ private static _values;
7
+ private static _valueMap;
8
+ private static _nameMap;
9
+ constructor(value: T, name: string, description?: string | undefined);
10
+ static values<T extends Enum<any>>(this: typeof Enum): T[];
11
+ static fromValue<T extends Enum<any>>(this: any, value: T['value']): T;
12
+ static fromName<T extends Enum<any>>(this: typeof Enum, name: string): T;
13
+ static setOf<T extends Enum<any>>(this: new () => T, ...items: T[]): Set<T>;
14
+ static enumMap<T extends Enum<any>, V>(this: typeof Enum, map: Record<string | number, V>): Map<T, V>;
15
+ toString(): string;
16
+ valueOf(): T;
17
+ }
18
+ export { Enum };
19
+ export type { EnumValueType };
package/dist/index.js ADDED
@@ -0,0 +1,63 @@
1
+ class Enum {
2
+ constructor(value, name, description) {
3
+ this.value = value;
4
+ this.name = name;
5
+ this.description = description;
6
+ const enumClass = this.constructor;
7
+ // 初始化存储结构
8
+ if (!Enum._values.has(enumClass)) {
9
+ Enum._values.set(enumClass, []);
10
+ Enum._valueMap.set(enumClass, new Map());
11
+ Enum._nameMap.set(enumClass, new Map());
12
+ }
13
+ // 注册当前枚举实例
14
+ Enum._values.get(enumClass).push(this);
15
+ Enum._valueMap.get(enumClass).set(value, this);
16
+ Enum._nameMap.get(enumClass).set(name, this);
17
+ }
18
+ // 获取所有枚举值
19
+ static values() {
20
+ return this._values.get(this) || [];
21
+ }
22
+ // 通过值获取枚举实例
23
+ static fromValue(value) {
24
+ const enumInstance = this._valueMap.get(this)?.get(value);
25
+ if (!enumInstance) {
26
+ console.error(`No enum value ${value} found`);
27
+ }
28
+ return enumInstance;
29
+ }
30
+ // 通过名称获取枚举实例
31
+ static fromName(name) {
32
+ const enumInstance = this._nameMap.get(this)?.get(name);
33
+ if (!enumInstance) {
34
+ console.error(`No enum name ${name} found`);
35
+ }
36
+ return enumInstance;
37
+ }
38
+ // 创建枚举集合
39
+ static setOf(...items) {
40
+ return new Set(items);
41
+ }
42
+ // 创建枚举映射表
43
+ static enumMap(map) {
44
+ const result = new Map();
45
+ for (const [key, value] of Object.entries(map)) {
46
+ const enumKey = isNaN(Number(key)) ? this.fromName(key) : this.fromValue(key);
47
+ result.set(enumKey, value);
48
+ }
49
+ return result;
50
+ }
51
+ // 重写toString方法
52
+ toString() {
53
+ return this.name;
54
+ }
55
+ // 重写valueOf方法
56
+ valueOf() {
57
+ return this.value;
58
+ }
59
+ }
60
+ Enum._values = new Map();
61
+ Enum._valueMap = new Map();
62
+ Enum._nameMap = new Map();
63
+ export { Enum };
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "ts-enum-next",
3
+ "version": "1.0.0",
4
+ "description": "Ultimate Enum Enhancement for TypeScript",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "keywords": [
8
+ "typescript",
9
+ "enum",
10
+ "enhancement",
11
+ "utility",
12
+ "enum-next",
13
+ "java"
14
+ ],
15
+ "author": "rico",
16
+ "license": "ISC",
17
+ "devDependencies": {
18
+ "typescript": "^5.8.3"
19
+ },
20
+ "scripts": {
21
+ "build": "tsc"
22
+ }
23
+ }
package/src/index.ts ADDED
@@ -0,0 +1,78 @@
1
+ type EnumValueType = number | string;
2
+
3
+ abstract class Enum<T extends EnumValueType> {
4
+ private static _values: Map<typeof Enum, Enum<any>[]> = new Map();
5
+ private static _valueMap: Map<typeof Enum, Map<EnumValueType, Enum<any>>> = new Map();
6
+ private static _nameMap: Map<typeof Enum, Map<string, Enum<any>>> = new Map();
7
+
8
+ constructor(
9
+ public readonly value: T,
10
+ public readonly name: string,
11
+ public readonly description?: string
12
+ ) {
13
+ const enumClass = this.constructor as typeof Enum;
14
+
15
+ // 初始化存储结构
16
+ if (!Enum._values.has(enumClass)) {
17
+ Enum._values.set(enumClass, []);
18
+ Enum._valueMap.set(enumClass, new Map());
19
+ Enum._nameMap.set(enumClass, new Map());
20
+ }
21
+
22
+ // 注册当前枚举实例
23
+ Enum._values.get(enumClass)!.push(this);
24
+ Enum._valueMap.get(enumClass)!.set(value, this);
25
+ Enum._nameMap.get(enumClass)!.set(name, this);
26
+ }
27
+
28
+ // 获取所有枚举值
29
+ static values<T extends Enum<any>>(this: typeof Enum): T[] {
30
+ return (this._values.get(this) as T[]) || [];
31
+ }
32
+
33
+ // 通过值获取枚举实例
34
+ static fromValue<T extends Enum<any>>(this: any, value: T['value']): T {
35
+ const enumInstance = this._valueMap.get(this)?.get(value);
36
+ if (!enumInstance) {
37
+ console.error(`No enum value ${value} found`);
38
+ }
39
+ return enumInstance as T;
40
+ }
41
+
42
+ // 通过名称获取枚举实例
43
+ static fromName<T extends Enum<any>>(this: typeof Enum, name: string): T {
44
+ const enumInstance = this._nameMap.get(this)?.get(name);
45
+ if (!enumInstance) {
46
+ console.error(`No enum name ${name} found`);
47
+ }
48
+ return enumInstance as T;
49
+ }
50
+
51
+ // 创建枚举集合
52
+ static setOf<T extends Enum<any>>(this: new () => T, ...items: T[]): Set<T> {
53
+ return new Set(items);
54
+ }
55
+
56
+ // 创建枚举映射表
57
+ static enumMap<T extends Enum<any>, V>(this: typeof Enum, map: Record<string | number, V>): Map<T, V> {
58
+ const result = new Map<T, V>();
59
+ for (const [key, value] of Object.entries(map)) {
60
+ const enumKey = isNaN(Number(key)) ? (this.fromName(key) as T) : (this.fromValue(key as any) as T);
61
+ result.set(enumKey, value);
62
+ }
63
+ return result;
64
+ }
65
+
66
+ // 重写toString方法
67
+ toString(): string {
68
+ return this.name;
69
+ }
70
+
71
+ // 重写valueOf方法
72
+ valueOf(): T {
73
+ return this.value;
74
+ }
75
+ }
76
+
77
+ export { Enum };
78
+ export type { EnumValueType };
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ESNext",
5
+ "esModuleInterop": true,
6
+ "strict": true,
7
+ "skipLibCheck": true,
8
+ "rootDir": "./src",
9
+ "outDir": "./dist",
10
+ "declaration": true,
11
+ "incremental": false,
12
+ "baseUrl": "./",
13
+ "moduleResolution": "node"
14
+ },
15
+ "include": ["src"]
16
+ }