Understanding TypeScript Mapped Types

Understanding TypeScript Mapped Types

Discover how Mapped Types and Utility Types work in TypeScript.

Getting Started with TypeScript Mapped Types

TypeScript, the superhero of JavaScript with static typing, has a cool feature called mapped types. These let you transform existing types into new ones, saving time and reducing errors. Let’s break it down.

What are Mapped Types?

Mapped types let you create new types by transforming the properties of existing ones. Think of it as making a copy of a type but with some changes.

Simple Syntax

Here’s a basic way to understand it:

type MappedType<T> = {
  [Key in keyof T]: SomeTransformation<T[Key]>;
};
  • T is your original type.

  • Key in keyof T means you go through each property in T.

  • SomeTransformation<T[Key]> is where you apply your change to each property.

Practical Examples

Let’s see some real-world examples to make this clearer.

  1. Making All Properties Optional

If you want to make every property in a type optional, use Partial:

type Partial<T> = {
  [Key in keyof T]?: T[Key];
};

Example:

interface User {
  name: string;
  age: number;
}

type OptionalUser = Partial<User>;
// Result: { name?: string; age?: number; }

In OptionalUser, both name and age are now optional.

  1. Making All Properties Read-Only

To make every property read-only, use Readonly:

type Readonly<T> = {
  readonly [Key in keyof T]: T[Key];
};

Example:

type ReadonlyUser = Readonly<User>;
// Result: { readonly name: string; readonly age: number; }

In ReadonlyUser, you can’t change name or age once they’re set.

  1. Changing All Property Types to string

If you need every property to be a string, use this:

type Stringify<T> = {
  [Key in keyof T]: string;
};

Example:

type StringifiedUser = Stringify<User>;
// Result: { name: string; age: string; }

In StringifiedUser, both name and age are now string types.

  1. Making All Properties Nullable

To make each property null or its original type, use Nullable:

type Nullable<T> = {
  [Key in keyof T]: T[Key] | null;
};

Example:

type NullableUser = Nullable<User>;
// Result: { name: string | null; age: number | null; }

In NullableUser, name and age can now also be null.

  1. Creating a Type for Full Names

Let's create a mapped type where keys can be anything, and all values are string:

type GiveMeaningFullName = {
  [key: string]: string;
};

Example:

const userFullNames: GiveMeaningFullName = {
  firstName: "John",
  lastName: "Doe",
  nickname: "Johnny"
};
// Result: { firstName: "John", lastName: "Doe", nickname: "Johnny" }

In GiveMeaningFullName, you can have any key as long as the value is a string.

Why Use Mapped Types?

  • Reusability: Write a transformation once, use it everywhere.

  • Consistency: Keep all your type changes uniform.

  • Clarity: Your code becomes easier to understand and maintain.

Conclusion

Mapped types are a fantastic feature in TypeScript that help you transform types easily. Whether you need optional properties, read-only properties, or different types altogether, mapped types make it simple.

Try using mapped types in your next TypeScript project and see how they can make your code cleaner and more manageable!