Reputation: 1275
Is there a way for transforming enums in Typescript? For example. I have an original enum
enum original {
VALUE_1
VALUE_2
}
I'd like to transform uppercase to lowercase, as
enum original {
value_1
value_2
}
Is it possible?
Upvotes: 0
Views: 1154
Reputation: 328433
In general, you can use write a function called lowercaseKeys()
to transform the keys of any object to lowercase, and then assert that such a function returns a strongly typed result. The return type involves key remapping to make a mapped type where the string literal keys into their lowercase counterparts via the Lowercase
intrinsic string manipulation type:
function lowercaseKeys<T extends object>(obj: T): {
[K in keyof T as K extends string ? Lowercase<K> : K]: T[K]
} {
return Object.fromEntries(
Object.entries(obj).map(([k, v]) => [k.toLowerCase(), v])
) as any;
}
Again, this should work for any object:
const example = lowercaseKeys({ STR: "hello", NUM: Math.PI });
/* const example: {
str: string;
num: number;
} */
console.log(example.num.toFixed(2)); // 3.14
You can see that at runtime, example
has keys named str
and num
, and the compiler is aware of this.
An enum
is also an object with keys and values, so you can transform it the same way:
const LowercaseEnum = lowercaseKeys(OriginalEnum);
/* const LowercaseEnum: {
[x: number]: string;
readonly value_1: OriginalEnum.VALUE_1;
readonly value_2: OriginalEnum.VALUE_2;
} */
console.log(LowercaseEnum.value_1.toFixed()); // "0"
console.log(LowercaseEnum.value_2.toFixed()); // "1"
Hooray!
Well, that's great as far as it goes. But note that an enum
also has some special features apart from a regular object. (See this answer for a more in-depth description of this differences.) For example, the name of an enum
can also be used as a type corresponding to the union of its values:
interface Okay {
e: OriginalEnum;
}
But LowercaseEnum
is just an object and was not declared as an enum
; there is no type named LowercaseEnum
:
interface Oops {
e: LowercaseEnum; // error
// ~~~~~~~~~~~~~
// 'LowercaseEnum' refers to a value,
// but is being used as a type here.
}
If you want such a type, you must make it:
type LowercaseEnum = OriginalEnum; // same values, so same type
Another difference is that a true numeric enum
like OriginalEnum
has a reverse mapping, where if OriginalEnum.VALUE_1
is 0
, then OriginalEnum[0]
is "VALUE_1"
:
console.log(OriginalEnum[0]); // "VALUE_1" as expected
But the transformed version doesn't have a useful reverse mapping, because only its keys have been changed; its values are untouched:
console.log(LowercaseEnum[0]); // still "VALUE_1", unexpected?
So, please be careful when using something like LowercaseEnum
: while there are similarities, it's not a true enum
.
Upvotes: 2