Typescript – Consider using a mapped object type instead

I’m encountering an issue with the following code:

interface Foo { 
    [foo: "hello" | "world"]: string;
}

The error message I receive is:

An index signature parameter type cannot be a union type. Consider using a mapped object type instead.

Could someone please explain what a mapped object type is and how I can use it to resolve this error?

Answer

Sure, let’s delve into this issue step by step:

Understanding the Problem

The error message you’re encountering, “An index signature parameter type cannot be a union type. Consider using a mapped object type instead”, is TypeScript’s way of telling you that you can’t use a union type as the parameter type in an index signature.

In your code, you’ve attempted to create an interface named Foo with an index signature that uses a union type as the key.

interface Foo { 
    [foo: "hello" | "world"]: string;
}

Here, foo is supposed to be a string literal type that can either be “hello” or “world,” but TypeScript doesn’t allow this.

The Solution: Mapped Object Types

To resolve this issue, you can indeed use mapped object types. Mapped types are a powerful feature in TypeScript that allow you to transform and create new types based on existing types.

In your case, you want to create a type where the keys are “hello” and “world,” and the values are always of type string.

Here’s how you can do it:

type Foo = {
    [key in "hello" | "world"]: string;
};

Now, let’s break down what we’ve done:

  1. We use the type keyword to define a new type called Foo.
  2. We use the in keyword in the square brackets to iterate over each key in the union type "hello" | "world". This is what makes it a mapped type.
  3. For each key ("hello" and "world"), we specify that the value should always be of type string. This ensures that the keys “hello” and “world” map to string values.

Benefits of Mapped Object Types

Mapped types offer several advantages:

  • Flexibility: Mapped types allow you to create new types based on existing ones, providing flexibility in defining complex type structures.
  • Type Safety: They provide strong type checking, ensuring that your code adheres to the specified type constraints.
  • Code Maintainability: By using mapped types, your code becomes more self-explanatory and easier to maintain, as it explicitly defines the expected type structure.

Final Code Example

Here’s the final code using the mapped object type:

type Foo = {
    [key in "hello" | "world"]: string;
};

Now, you have a Foo type where the keys are “hello” and “world,” and the values are always of type string. This should resolve the error you were facing.

In summary, mapped object types are a powerful tool in TypeScript for creating complex type structures while maintaining type safety.

In this case, we’ve used them to define an interface with specific key-value pairs, ensuring that the keys are of a predefined set and the values have a consistent type.

Related Posts: