Reputation: 783
I would like to iterate over an object with enum keys. Problem is that the types are always interfering and I would prefer to not cast everything.
enum MyEnum { A, B, C }
type MyMap = { [key in MyEnum]: string };
const myMap: MyMap = {
[MyEnum.A]: 'a?',
[MyEnum.B]: 'b',
[MyEnum.C]: 'c...',
};
If I try Object.keys
or for..in
it always shows errors.
Object.keys(myMap).forEach(key => {
const data = myMap[key]; // <= Error TS7017: Element implicitly has an 'any' type because type 'MyMap' has no index signature.
});
// same with: for (const key in myMap) {
Object.keys(myMap).forEach((key: MyEnum) => { // Error TS2345: Argument of ... Type 'string' is not assignable to type 'MyEnum'.
});
I could cast the key but can't even do it directly...
Object.keys(myMap).forEach(key => {
const data = myMap[key as MyEnum]; // Error TS2352: Conversion of type 'string' to type 'MyEnum' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
// have to do this but would prefer not to
const data2 = myMap[key as unknown as MyEnum];
});
There probably is a solution somewhere but I didn't use the right keywords and didn't find it :( (edit: or maybe not)
Upvotes: 0
Views: 816
Reputation: 783
The solution I'm most happy with now is adding a helper function that does the casting of the keys. This is also easily reusable for all kinds of similar objects.
export function objectKeys<Obj extends object>(obj: Obj): (keyof Obj)[] {
return Object.keys(obj) as (keyof Obj)[];
}
// with example from above
// no specific type for the map needed
const myMap = {
[MyEnum.A]: 'a?',
[MyEnum.B]: 'b',
[MyEnum.C]: 'c...',
};
objectKeys(myMap).forEach(key => {
// key: MyEnum
// if the enum has more values that are not part of the map (D..)
// the types are still correct => key: MyEnum.A | MyEnum.B | MyEnum.C
});
Note: It's not perfect. e.g. with arrays
objectKeys([]).forEach(key => {
// key: number | 'length' | ...
// would be perfect if it returned only `number` or even `never` (empty array)
});
Upvotes: 0
Reputation: 3387
If you don't want to use any
or unknown
const data = myMap[MyEnum[key as keyof typeof MyEnum]];
Upvotes: 2