Original AUG/18
In my case none of the above solutions worked, the reason was that I was casting the enum value to the enum object.
After that, I was trying to know if the enum was equivalent to another enum object... so I've created the following generic functions:
public static enumEquals<T>(e: any, e1: T, e2: T): boolean {
const v1 = this.enumValue(e, e1);
return v1 === this.enumValue(e, e2, typeof v1);
}
private static enumValue<T>(enumType: any, value: T, validType?: string) {
let v = enumType[value];
if (!validType) {
return v;
}
if (typeof v !== validType) {
v = enumType[v];
}
if (typeof v !== validType) {
v = enumType[v];
}
return v || null;
}
This is an example of my test case:
enum SomeEnum {
VALUE1, VALUE2, VALUE3, VALUE_DEF
}
const enumRefKey = localStorage.getItem('someKey');
const parsedEnum = SomeEnum[enumRefKey] || SomeEnum.VALUE_DEF;
console.log(parsedEnum);
if (parsedEnum === SomeEnum.VALUE_DEF) {
// do stuff
}
That code didn't worked, after I've tried the solutions given here at this questions, I've found that when enumRefKey
is valid console.log(parsedEnum)
was printing numbers and the text VALUE_DEF
when is not. The same result happend using all other solutions:
- parsedEnum as SomeEnum
- parsedEnum.valueOf()
- SomeEnum[parsedEnum]
The solution using the generic methods looks like this:
enum SomeEnum {
VALUE1, VALUE2, VALUE3, VALUE_DEF
}
const enumRefKey = localStorage.getItem('someKey');
const parsedEnum = SomeEnum[enumRefKey] || SomeEnum.VALUE_DEF;
console.log(parsedEnum);
if (this.enumEquals(SomeEnum, parsedEnum, SomeEnum.VALUE_DEF) {
// do stuff
}
Update SEP/21
Best way to avoid all the issues related to enums
in TypeScript
comparison is to declare them like the following example.
Instead of this:
enum SomeEnum {
VALUE1, VALUE2, VALUE3
}
Do this:
enum SomeEnum {
VALUE1 = 'VALUE1', VALUE2 = 'VALUE2', VALUE3 = 'VALUE3'
}
This way from now you won't need to cast nor convert enum values to enum objects, and if you need to it'll always work. With this solution, all of the following examples are valid, and they'll return true
:
console.log(SomeEnum['VALUE1'] === 'VALUE1'); // prints 'true'
console.log(SomeEnum['VALUE1'] === SomeEnum.VALUE1); // prints 'true'
console.log(SomeEnum['VALUE1'] === 'VALUE1' as SomeEnum); // prints 'true'
console.log(SomeEnum['VALUE1'] === 'VALUE1'); // prints 'true'
console.log(SomeEnum['VALUE1'] === (<SomeEnum>'VALUE1')); // prints 'true'
console.log(SomeEnum.VALUE1 === 'VALUE1' as SomeEnum); // prints 'true'
console.log(SomeEnum.VALUE1 === (<SomeEnum>'VALUE1')); // prints 'true'
console.log(SomeEnum.VALUE1 === 'VALUE1'); // prints 'true'
Culprit
The reason for all this issues is that when TypeScript
is compiled to JavaScript
enums are parsed as objects
like this
// this enum at TS
enum SomeEnum {
VALUE1, VALUE2, VALUE3
}
// is parsed to JS like this:
{
VALUE1: 1, VALUE2: 2, VALUE3: 3, 1: 'VALUE1', 2: 'VALUE2', 3: 'VALUE3'
}
As you can see, once the enum is parsed to JS
the reason for all the comparison issues becomes obvious, as we mistakenly may be comparing string
vs number
which may end up in false-positive results. The following is the second enum parsed to JS which works way better:
// this enum at TS
enum SomeEnum {
VALUE1 = 'VALUE1', VALUE2 = 'VALUE2', VALUE3 = 'VALUE3'
}
// is parsed to JS like this:
{
'VALUE1': 'VALUE1', 'VALUE2': 'VALUE2', 'VALUE3': 'VALUE3'
}