Borislav Hadzhiev
Sun Mar 13 2022·2 min read
Photo by Chuttersnap
The error "An index signature parameter type cannot be a literal type or a
generic type" occurs when we use an incompatible type for an index signature
parameter, e.g. union or enum. To solve the error use a mapped object type, e.g.
type MyType = {[key in MyUnion]: string;}
.
Here are 2 examples of how the error occurs.
// 👇️ Using ENUMS 👇️ enum EmailStatus { Read = 'READ', Unread = 'UNREAD', Draft = 'DRAFT', } type Status = { // ⛔️ Error: An index signature parameter type // cannot be a literal type or generic type. // Consider using a mapped object type instead.ts(1337) [key: EmailStatus]: string; }; // 👇️ Using UNION type 👇️ type EmailStatuses = 'Read' | 'Unread' | 'Draft'; type StatusFromUnion = { // ⛔️ Error: An index signature parameter type // cannot be a literal type or generic type. // Consider using a mapped object type instead.ts(1337) [key: EmailStatus]: string; };
We are using an
index signature
in the Status
and StatusFromUnion
types, but the type of the key is not one
of the allowed types, which are string
, number
, symbol
or template literal
type.
To solve the error, use mapped types.
// 👇️ Using Enums enum EmailStatus { Read = 'READ', Unread = 'UNREAD', Draft = 'DRAFT', } // 👇️ make sure you use type here (not interface) type Status = { [key in EmailStatus]: string; }; // 👇️ Using Union type type EmailStatuses = 'Read' | 'Unread' | 'Draft'; // 👇️ make sure you use type here (not interface) type StatusFromUnion = { [key in EmailStatuses]: string; };
Notice that we are using the in
keyword in our index signature. This is used
to refer to the specific properties in the enum and union.
Make sure you are using a type alias and not an interface when using mapped types.
If you use a mapped type in an interface instead of a type alias, you would get the error: "A mapped type may not declare properties or methods".
interface Status { // ⛔️ Error: A mapped type may not declare // properties or methods.ts(7061) [key in EmailStatus]: string; };
In the example, we use mapped types to take all of the properties of the enum
and union and change their values to be of type string
.
A different approach to solve the "An index signature parameter type cannot be a
literal type or a generic type" error is to use the Record
utility type.
// 👇️ Using Enums enum EmailStatus { Read = 'READ', Unread = 'UNREAD', Draft = 'DRAFT', } type Status = Record<EmailStatus, string> // 👇️ Using Union type type EmailStatuses = 'Read' | 'Unread' | 'Draft'; type StatusFromUnion = Record<EmailStatus, string>
This code snippet achieves the same result as the one that used mapped types.
The Record utility type constructs an object type based on the provided types for the keys and values.