Oliver
Oliver

Reputation: 1644

TypeScript iterate over string enum with the enum type instead of string type

I have a string enum in TypeScript, and I want to iterate over it like below. However, when I do this the type of the iterator is a string instead of the enum type.

enum Enum { A = 'a', B = 'b' };

let cipher: { [key in Enum]: string };

for (const letter in Enum) {
    cipher[letter] = 'test'; // error: letter is of type 'string' but needs to be 'Enum'
}

The exact error I get is this:

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ a: string; b: string; }'.
  No index signature with a parameter of type 'string' was found on type '{ a: string; b: string; }'.ts(7053)

This seems strange as it's guaranteed the letter is an Enum. Is there any way to work around this?

Upvotes: 4

Views: 1553

Answers (1)

robertgr991
robertgr991

Reputation: 181

I'll post my comments as an answer so the questions won't remain unanswered.

The type of cipher will have the keys as the values of Enum, that is:

let cipher: {
  a: string;
  b: string;
}

because you are using a string enum. But when iterating with for...in you iterate over the enumerable properties of the generated object, those properties are ['A', 'B'] because the generated object(TypeScript v4) would be:

var Enum;
(function (Enum) {
    Enum["A"] = "a";
    Enum["B"] = "b";
})(Enum || (Enum = {}));

So you need to iterate over the enum values. For this you can use Object.values to get an array of it's values and for...of to iterate over it. This way, letter type will be Enum.

for (const letter of Object.values(Enum)) {
    cipher[letter] = 'test'; // error: letter is of type 'string' but needs to be 'Enum'
}

I never used for...in with an enum before but I would have expected the compiler to have enough information so the for...in strictly types letter to a union of "A" | "B" but it seems that it widens the type to string.

Upvotes: 4

Related Questions