TypeScript如何将键名相同的字符串枚举转换为另一个枚举?
同键名字符串枚举转换实现方案
TypeScript 字符串枚举确实不提供数字枚举自带的反向映射能力,针对两个键名完全对齐的字符串枚举转换场景,不需要hack语言特性,通过自建反向映射表加泛型约束就能实现完全类型安全的转换。
实现思路
TS枚举编译后本质是普通的键值对对象,既然两个枚举的键名始终完全一致,只需要先拿到RawStatusEnum某个值对应的键名,再用这个键名去StatusEnum里取值就能得到结果。类型层面通过泛型和映射类型约束,保证入参和返回值一一对应,不会返回宽泛的枚举联合类型。
完整代码
enum StatusEnum { SUCCESS = 'SUCCESS', ERROR = 'ERROR', WARN = 'WARN', DEBUG = 'DEBUG', } enum RawStatusEnum { SUCCESS = 'Success', ERROR = 'Error', WARN = 'Warn', DEBUG = 'Debug', } // 初始化时一次性生成 RawStatusEnum 值到键名的反向映射表 const rawValueToKeyMap: Record<RawStatusEnum, keyof typeof StatusEnum> = Object .entries(RawStatusEnum) .reduce((map, [enumKey, enumValue]) => { map[enumValue as RawStatusEnum] = enumKey as keyof typeof StatusEnum; return map; }, {} as Record<RawStatusEnum, keyof typeof StatusEnum>); function cast<T extends RawStatusEnum>(raw: T): typeof StatusEnum[typeof rawValueToKeyMap[T]] { return StatusEnum[rawValueToKeyMap[raw]]; }
使用效果
调用时能得到精确的类型推导,不存在类型丢失问题:
const rawEnumValue = RawStatusEnum.ERROR; // 类型为 RawStatusEnum.ERROR const normalEnumValue = cast(rawEnumValue); // 自动推导为 StatusEnum.ERROR,完全匹配预期
边界说明
- 因为类型约束的存在,如果后续两个枚举的键名出现不一致(比如其中一个新增/删除了字段、改了键名),TS会直接在映射表或者cast调用处抛类型错误,不需要额外写校验逻辑
- 反向映射表只在代码加载时生成一次,运行时调用cast的开销就是普通对象属性读取,没有性能问题
- 只要遵循枚举值唯一的常规写法,就不会出现反向映射键冲突的问题;如果故意给同一个枚举设置重复值,后遍历到的键会覆盖之前的映射,属于不符合枚举设计的异常场景。
内容的提问来源于stack exchange,提问作者Denys Rybkin
相关产品推荐
相关产品推荐

