如何使用相同的键将字符串枚举转换为另一个枚举?

How to cast string enum to another enum with the same keys?

由这 2 个具有相同键的字符串枚举给出:

enum StatusEnum {
    SUCCESS = 'SUCCESS',
    ERROR = 'ERROR',
    WARN = 'WARN',
    DEBUG = 'DEBUG',
}

enum RawStatusEnum {
    SUCCESS = 'Success',
    ERROR = 'Error',
    WARN = 'Warn',
    DEBUG = 'Debug',
}

我想将枚举 RawStatusEnum 的值转换为枚举 StatusEnum 的值,即:

const rawEnumValue = RawStatusEnum.ERROR // RawStatusEnum
const normalEnumValue = cast(rawEnumValue) // StatusEnum

但我在打字方面遇到问题......我已经了解了打字稿中的反向映射 ,但反向映射仅适用于数字枚举。提前致谢。

如您所述,string enums don't automatically get a reverse mapping,因此从值中获取键并不像查找那么简单。

但是,编写辅助函数来为字符串枚举生成反向映射是相当简单的。但是编译器无法验证它是否已正确实现,因此您需要 type assertion。例如:

const reverseStringEnum = <T extends Record<keyof T, string>>(e: T) =>
  Object.fromEntries(Object.entries(e).map(([k, v]) => [v, k])) as 
   { [K in keyof T as T[K]]: K };

它也使用 Object.entries() and Object.fromEntries() methods to split the enum object into key-value pairs and then put it back together with the keys and values swapped. The input object type is T, and the output object type is {[K in keyof T as T[K]]: K}, which uses key remapping 交换键和值类型。

让我们在 RawStatusEnum 上测试一下:

const RawStatusReverseEnum = reverseStringEnum(RawStatusEnum);
/* const RawStatusReverseEnum: {
    readonly Success: "SUCCESS";
    readonly Error: "ERROR";
    readonly Warn: "WARN";
    readonly Debug: "DEBUG";
} */

看起来不错。现在我们可以通过进行一对查找将 RawStatusEnum“转换”为 StatusEnum。我们在 RawStatusReverseEnum 中查找键,然后使用键查找 StatusEnum 中的值:

const castRawToNormal = <T extends RawStatusEnum>(t: T) =>
  StatusEnum[RawStatusReverseEnum[t]];

让我们使用它:

const rawEnumValue = RawStatusEnum.ERROR // RawStatusEnum

const normalEnumValue = castRawToNormal(rawEnumValue);
// const normalEnumValue: StatusEnum.ERROR

console.log(normalEnumValue); // "ERROR"

看起来不错。编译器甚至知道 normalEnumValue 的类型是 StatusEnum.ERROR.

Playground link to code