Mapped Types with Typescript
Tags: typescript, beginners, webdev, tutorial
Published: 2022-07-08 17:49:47

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 `PropertyKey`s (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:

```typescript
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
}
```

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

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

## 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:

```typescript
type MappedToBoolean <Type> = {
    [Property in keyof Type]+?: Type[Property]
}
```

## Mapping using the `as` keyword

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

```typescript
type MappedTypeWithNewProperties<Type> = {
    [Properties in keyof Type as NewKeyType]: Type[Properties]
}
```

## 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.

```typescript
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>`
```

If you enjoy reading this article, you can support my hobby by [buying me a coffee](https://www.buymeacoffee.com/kayode).