Given by these 2 string enums with always the same keys:
enum StatusEnum {
SUCCESS = 'SUCCESS',
ERROR = 'ERROR',
WARN = 'WARN',
DEBUG = 'DEBUG',
}
enum RawStatusEnum {
SUCCESS = 'Success',
ERROR = 'Error',
WARN = 'Warn',
DEBUG = 'Debug',
}
I want to cast value of enum RawStatusEnum to value of enum StatusEnum, that is:
const rawEnumValue = RawStatusEnum.ERROR // RawStatusEnum
const normalEnumValue = cast(rawEnumValue) // StatusEnum
But I have problems with typings and ... I've learnt about reverse mapping in typescript here, but reverse mapping works only for numeric enums. Thanks in advance.
As you noted, string enums don't automatically get a reverse mapping, so getting the key from a value isn't as simple as a lookup.
However, it's fairly straightforward to write a helper function to generate a reverse mapping for a string enum. But the compiler can't verify that it's implemented properly so you'll need a type assertion. For example:
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 };
It uses the 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 to swap the key and value types also.
Let's test it out on RawStatusEnum:
const RawStatusReverseEnum = reverseStringEnum(RawStatusEnum);
/* const RawStatusReverseEnum: {
readonly Success: "SUCCESS";
readonly Error: "ERROR";
readonly Warn: "WARN";
readonly Debug: "DEBUG";
} */
Looks good. And now we can "cast" a RawStatusEnum to a StatusEnum by doing a pair of lookups. We lookup the key in RawStatusReverseEnum and then use the key to lookup the value in StatusEnum:
const castRawToNormal = <T extends RawStatusEnum>(t: T) =>
StatusEnum[RawStatusReverseEnum[t]];
Let's use it:
const rawEnumValue = RawStatusEnum.ERROR // RawStatusEnum
const normalEnumValue = castRawToNormal(rawEnumValue);
// const normalEnumValue: StatusEnum.ERROR
console.log(normalEnumValue); // "ERROR"
Looks good. The compiler even knows that normalEnumValue will be of type StatusEnum.ERROR.
Playground link to code
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With