Reputation: 59365
I have an enum Animals
and I am trying to create a function that takes a value and the entire enum object returns the value as an emum if it is valid.
enum Animals {
WOLF = 'wolf',
BADGER = 'badger',
CAT = 'cat',
}
const coerseEnum = <T> (s, E: T): T | undefined => {
const keys = Object.keys(E);
const values = keys.map(k => E[k as any]);
const obj = lodash.zipObject(keys, values);
const key = lodash.findKey(obj, item => item === s);
if (!key) return undefined;
return E[key];
};
const x: Animals | undefined = coerseEnum('cat', Animals);
console.log(x);
However it's not casting to Animals
but typeof Animals
.
Upvotes: 0
Views: 782
Reputation: 249636
An enum has a type for the item of an enum (Animal
) but also a type for the object that holds the values at runtime. This object is also named Animal
, but it is not of type Animal
since it contains all the entries for the enum. If we are starting from the type of the enum container object (typeof Animal
) to get back to the type of the enum we need to write typeof Animal[keyof typeof Animal]
In your case, T
is inferred to typeof Animal
, the enum container object since that is what you are passing to the function. TO get back to the enum type we need to do T[keyof T]
enum Animals {
WOLF = 'wolf',
BADGER = 'badger',
CAT = 'cat',
}
const coerseEnum = <T> (s: string, E: T): T[keyof T] | undefined => {
const keys = Object.keys(E);
const values = keys.map(k => E[k as any]);
const obj = lodash.zipObject(keys, values);
const key = lodash.findKey(obj, item => item === s);
if (!key) return undefined;
return E[key];
};
const x: Animals | undefined = coerseEnum('cat', Animals);
console.log(x);
Note
We usually don't notice this, but when we use Animal
in a type annotation it is the type of an enum item, when we use Animal
as a value we are talking about the container object which is not of type Animal
. Just wanted to make that clear in case the previous paragraph was not 100% clear
Upvotes: 3