Mapped Types with Typescript

zt4ff_1

Kayode

Posted on July 8, 2022

Mapped Types with Typescript

Mapped type is one of the type manipulations you can do with Typescript. It is useful when you want to derive a type from another type but have the properties of the new type go through some manipulation.

The concept at its core is pretty similar to Array.map() method in Javascript. If you want to derive a new array from an existing array, rather than repeating the new array, you can make use of the Array.map() method and iterate through the old array to generate a similar/different array.

This is basically what we are trying to do with mapped types.

What is a Mapped Type

A mapped type is a generic type which uses a union of PropertyKeys (frequently created via a [keyof](https://www.typescriptlang.org/docs/handbook/2/indexed-access-types.html)) to iterate through keys to create a type.

Let’s say you have a Type with functions as its properties and you want to generate a new type with the same properties but as booleans, you can do this:

type MappedToBoolean <Type> = {
    [Property in keyof Type]: boolean
}

type Animal = {
    fly: () => void;
    run: () => void;
    swim: () => void
}

type NewAnimal = MappedToBoolean<Animal>

const dog: NewAnimal =  {
    fly: false,
    run: true,
    swim: true
}
Enter fullscreen mode Exit fullscreen mode

Doing this, below, would result in a type error:

const dog: NewAnimal =  {
    fly: () => undefined, // '() => undefined' is not assignable to type 'boolean'
    run: true,
    swim: true
}
Enter fullscreen mode Exit fullscreen mode

What are Mapping Modifiers

There are two additional modifiers which can be applied during mapping: readonly and ? which affect mutability and optionality respectively.

You can remove or add these modifiers by prefixing them with these - (to add) or + (to delete).

For instance, to map through a type and make all its properties optional, you can just add the + modifier as such:

type MappedToBoolean <Type> = {
    [Property in keyof Type]+?: Type[Property]
}
Enter fullscreen mode Exit fullscreen mode

Mapping using the as keyword

You can remap the type of the keys into other types as such:

type MappedTypeWithNewProperties<Type> = {
    [Properties in keyof Type as NewKeyType]: Type[Properties]
}
Enter fullscreen mode Exit fullscreen mode

Use Cases

Knowing how to manipulate different types can give you the control to efficiently create and manage modular or expansible types.

A simple scenario where I used this once was when I need a function that can take the sub-type of an object and search through an array of objects to see if a super object exists.

A sub-type of an object is literally one where all the properties can be optional so I created a new type of the existing type where all the properties are optional.

type MakePropertiesOptional<Type> = {
    [Property in keyof Type]+?: Type[Property]
}

type Person = {
    name: string;
    age: number;
    school: string;
    state: string;
    number: string;
    country: string
}

function searchArrayOfPersons(person: MakePropertiesOptional<Person>) {
    // .. some more codes
    return undefined
}

searchArrayOfPersons({name: "Kayode"})

searchArrayOfPersons({address: "some address"})
// Type Error: '{ address: string}': is not assignable to parameter
// of 'MakePropertiesOptional<Person>`
Enter fullscreen mode Exit fullscreen mode

If you enjoy reading this article, you can support my hobby by buying me a coffee.

💖 💪 🙅 🚩
zt4ff_1
Kayode

Posted on July 8, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related