Skip to content

TypeScript ships built-in advanced types for everyday use, but books, documentation, and online articles don't always explain them clearly. This article is a reference for anyone who needs the basics laid out.

Prerequisite: keyof

Before understanding advanced types, you need to understand keyof:

typescript
interface User {
  name: string;
  mobile: string;
}

type keys = keyof User; // Equivalent to: type keys = 'name' | 'mobile'

keyof extracts an interface's keys. Understanding keyof is essential for the advanced types that follow: Record and Pick.

Prerequisite: Mapped Types

Mapped types allow you to quickly create types:

typescript
type NewUser = {
  [K in 'name' | 'mobile']: string;
};

// This is equivalent to:
type NewUser = {
  name: string;
  mobile: string;
}

Combined with keyof:

typescript
interface User {
  name: string;
  mobile: string;
}

type NewUser = {
  [K in keyof User]: string;
};

Now that the prerequisites are covered, let's move on to TypeScript's advanced types.

Record Type

Record is widely used — it lets you quickly create a type. Let's look at its source code:

typescript
/**
 * Construct a type with a set of properties K of type T
 */
type Record<K extends keyof any, T> = {
    [P in K]: T;
};

It's straightforward. Combined with the prerequisites:

typescript
type User = Record<'name' | 'mobile', string>;

// This is equivalent to:
type User = {
  name: string;
  mobile: string;
}

Partial Type

The Partial type makes all properties of a type optional. Source code:

typescript
/**
 * Make all properties in T optional
 */
type Partial<T> = {
    [P in keyof T]?: T[P];
};

Usage:

typescript
type User = {
  name: string;
  mobile: string;
}

type NewUser = Partial<User>;

// Equivalent to:
type NewUser = {
  name?: string;
  mobile?: string;
}

Combined with Record:

typescript
type NewUser = Partial<Record<'name' | 'mobile', string>>;

Readonly Type

As the name suggests, Readonly makes all properties of the passed type read-only. Source code:

typescript
/**
 * Make all properties in T readonly
 */
type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};

Usage:

typescript
type User = Readonly<Record<'name' | 'mobile', string>>;

// Equivalent to:
type User = {
  readonly name: string;
  readonly mobile: string;
}

Pick Type

Pick selects specific properties from a type and returns a new type. Source code:

typescript
/**
 * From T, pick a set of properties whose keys are in the union K
 */
type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};

Usage:

typescript
type User = {
  name: string;
  mobile: string;
  address: string;
}

type NewUser = Pick<User, 'name' | 'mobile'>;

// Equivalent to:
type NewUser = {
  name: string;
  mobile: string;
}

Summary

These advanced types were introduced by TypeScript back in 2016 and have been widely adopted in packages and frameworks. They're quite useful day to day, so I've noted them here.