0

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)

2 Answers 2

2

If you don't want to use any or unknown

    const data = myMap[MyEnum[key as keyof typeof MyEnum]];
Sign up to request clarification or add additional context in comments.

Comments

0

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)
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.