I can describe an indexed type restriction in an object type notation such as the following:
enum Enum {
A = 0,
B = 1,
}
type EnumMap = {
[P in Enum]: string;
}
But, surprisingly, the same doesn't seem to be possible when using index notation in an interface:
enum Enum {
A = 0,
B = 1,
}
interface EnumMap {
[P in Enum]: string;
}
The error is:
A computed property name must be of type 'string', 'number', 'symbol', or 'any'.
Is there any reason why this is so? By definition, enums in TypeScript can have only string or number values (or even both, but that's not recommended), and I thought the enum itself would work like a union type for all the values it lists.
Investigating a bit further, I also found that, in the following example, EnumValues
has type number
, instead of (what I expected to be) 0 | 1
. Again, why is this so?
const Enum = {
A: 0,
B: 1
};
type EnumKeys = keyof typeof Enum;
type EnumValues = typeof Enum[EnumKeys];
The index signature is a fitting way to handle objects with properties we know nothing about. Its syntax describes a regular property, but instead of writing a standard property name, we define the type of keys and the properties.
An enum type is a special data type that enables for a variable to be a set of predefined constants. The variable must be equal to one of the values that have been predefined for it. Common examples include compass directions (values of NORTH, SOUTH, EAST, and WEST) and the days of the week.
The error "No index signature with a parameter of type 'string' was found on type" occurs when we use a value of type string to index an object with specific keys. To solve the error, type the string as one of the object's keys using keyof typeof obj .
The error "Property is incompatible with index signature" occurs when a property is not compatible with the specified type of the index signature. To solve the error, change the type of the property or use a union to update the type in the index signature.
Regarding error in:
interface EnumMap {
[P in Enum]: string;
}
Enum is a special data structure in TypeScript and it is not assignable to string | number | symbol
.
COnsider this example:
const key = <T extends string | number | symbol>(t: T) => t
key(Enum) // error
Also, enum
has special behavior.
See this example:
const enm = (t: Enum) => t
// Argument of type 'typeof Enum' is not assignable to parameter of type 'Enum'
enm(Enum) // error
So there is a difference even between Enum
and typeof Enum
.
Let's go back to our problem.
Until TS 4.4 you were no allowed to use unions as an index signature in interfaces.
Consider this example without enum
:
interface EnumMap {
[P in 'a'|'b']: string; // error
}
Hence it is about TS restrictions an not about enums.
As for the second case:
const Enum = {
A: 0,
B: 1
};
type EnumKeys = keyof typeof Enum;
type EnumValues = typeof Enum[EnumKeys];
This is because const Enum
is mutable.
In order to obtain 1|0
, you should make it immutable:
const Enum = {
A: 0,
B: 1
} as const; // special syntax
type EnumKeys = keyof typeof Enum;
type EnumValues = typeof Enum[EnumKeys]; // 0 | 1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With