Learn TypeScript

Creating a mapped type

Creating a mapped type

In this lesson, we will learn what mapped types are and how to create them.

Understanding a mapped type

A mapped type is the process of creating a new type by mapping type information from an existing type.

type MappedTypeName = { [K in UnionType]: ExistingType };

The in operator maps over each item in the union type to create a new type. In other words, the in operator allows us to loop through each type in a union type. In a loop iteration, wach item in the union type is put in K, which becomes a key in the new type. So, the union type is usually a union of string literals. The type annotation in the mapped type is the type given to each key in the type.

So:

type ContactDetails = { [K in "name" | "email"]: string };

... creates the following type:

{
name: string;
email: string;
}

This becomes more useful when used with the keyof operator we learned about in the last lesson:

type MappedTypeName = {
[K in keyof ExistingType1]: ExistingType2;
};

This creates a new type containing the keys from another type.

An example

We are going to explore a useful example of a mapped type in the code editor below:

TypeScriptOpen exercise in CodeSandbox

The editor contains a generic Form interface and a contactForm variable that uses this interface for its type.

🤔

Can you spot a problem with the object assigned to contactForm?

🤔

Why doesn't a type error occur to surface this problem?

  • Update the errors type within the Form interface to use a mapped type based on T:
interface Form<T> {
...
errors: { [K in keyof T]: string };
}
  • A type error is now raised on emailAddress, which a great. So, change this to email.
🤔

A type error still exists on errors. What is the problem?

  • The problem can be resolved if we make the mapped keys optional in the errors type. Update the mapped type so that its keys are optional by placing a question mark (?) in front of the key's type annotation.

All the type errors are now resolved.

Great!

  • Add another property in the type passed into Form:
const contactForm: Form<{
...
mobile: string;
}> = {
...
};
  • Add a mobile number in the values object:
values: {
...
mobile: "0745 6723432"
},
  • Add an error for mobile in the errors object. Type this out manually and notice the intellisense.
errors: {
...
mobile: "You must add a mobile number"
},

Notice that no type errors are raised.

Nice!

Summary

Mapped types allow us to create new types based on an existing type. They are useful for handling generic data in a strongly-typed manner.

In the next lesson, we will learn about using type modifiers in mapped types.

© 2023 Carl Rippon
Privacy Policy
This site uses cookies. Click here to find out more