'How to check if a given string key exists in Enum?
I have an enum defined like this:
export enum someEnum {
None = <any>'',
value1 = <any>'value1',
value2 = <any>'value2',
value3 = <any>'value3'
}
For example, I want to check "value4" key exists in an enum. I should get false as value4 is not defined on the enum.
I tried if (someEnum['value4']) but got an error:
Element implicitly has an 'any' type because index expression is not of type 'number'.
Solution 1:[1]
You could use the in operator:
if ('value4' in someEnum) {
// ...
}
Solution 2:[2]
For TypeScript 3.7 with a target of es2017 or higher
enum EList {
ITEM_FOO = 'fooData',
ITEM_BAR = 'barData'
}
const lookingForKey = 'ITEM_BAR'
const lookingForValue = 'barData'
// test if `lookingForKey` exists within `EList`
console.log(Object.keys(EList).some((v) => v === lookingForKey))
// test if `lookingForValue` exists within `EList`
console.log(Object.values(EList).some((v) => v === lookingForValue))
Solution 3:[3]
Typescript enums are a little annoying because they have two sides - the atom used to name a value, and the actual value. These each have a different way to check them.
Let's use an example enum that represents actions a content blocker can take. We'll get a kebab-case value from our API but want to use a camelCase value in TS:
enum ActionType {
block = "block",
cssDisplayNone = "css-display-none",
ignorePreviousRules = "ignore-previous-rules"
}
Now if we wanted to check if it was valid to say ActionType.cssDisplayNone in our code, we can check that with the in operator. However, if we have a value from an API and we want to see if the value we got is an ActionType, that won't work!
const canBlockCss = 'cssDisplayNone' in ActionType; // Returns true
const isValidAction = 'css-display-none' in ActionType; // Returns false!
In this case, we need to write a type guard:
function isActionType(test: any): test is ActionType {
return (Object.values(ActionType).indexOf(test) !== -1);
}
const isValidAction = isActionType('css-display-none') // Returns true
This has the added bonus that if you have a variable of unknown type and pass it to a type guard, the return value will be included in Typescript's understanding of the variable, allowing you to cast it at the same time as you check it.
Solution 4:[4]
To understand how to check if a value exists in enum, one has to understand what it becomes after compilation. And it is nothing more than a good old JavaScript object populated by an IIFE (Immediately Invoked Function Expression).
Let us assume you have a simple string-based enum:
enum Test {
TEST = "test"
}
This is how the compiled JavaScript code looks like:
var Test;
(function (Test) {
Test["TEST"] = "test";
})(Test || (Test = {}));
Note that the result of this is simply:
var Test = {
"TEST": "test"
}
It means that, obviously, the in operator is enough to check if a key is present in the enum. It also is enough in case the value is equal to the key, but only accidentally.
Type guard is indeed a more viable solution, but it could also be improved by:
- Optimizing a little - a simple
for...inloop will do, in this case, we can even omit thehasOwnPropertyguard. - Making the type guard generic for reusability.
Note that val param is not simply T, but is a value in T (hence T[keyof T]):
function hasA<T>(obj : T, val: any) : val is T[keyof T] {
for(const k in obj) {
if( obj[k] === val ) {
return true;
}
}
return false;
};
Testing to make sure everything works:
var t = "something";
if(hasA(Test,t)) {
t //inferred as "Test"
}
var d = "any";
if( !hasA(Test, d) ) {
d //inferred as "string"
}
console.log( hasA( Test, "something" ) ); //true
console.log( hasA(Test, "anything") ); //false
Solution 5:[5]
For string-based enums where you want to check a value against the right side of the enum, this is the most succinct that I've found:
Object.values(someEnum).includes('value4')
This requires ES2017.
Solution 6:[6]
I know this is an old question, but if your use-case is simply checking strings against a (non-const) string-enum's values, then this is probably the way to go:
enum Example {
Foo = 'foo',
Bar = 'bar',
}
const ExampleVals = Object.values<string>(Example);
const isExample = (s: string): s is Example => ExampleVals.includes(s);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Ryan Cavanaugh |
| Solution 2 | tsujp |
| Solution 3 | Zack |
| Solution 4 | |
| Solution 5 | Stephen Horvath |
| Solution 6 |
