Reputation: 1644
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
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