Skip to content

TypeScript provides built-in advanced types to assist in daily development, but whether in books or documentation, the explanations aren't always clear, and online articles can be hard to digest. This article aims to record and help those who need it.

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'

As shown above, keyof extracts the keys of an interface. Understanding keyof is essential for the advanced types that follow: Record, Pick.

Prerequisite: Mapped Types

Mapped types allow you to quickly create types:

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

// The above code 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;
};

With prerequisites covered, let's move on to TypeScript's advanced types.

Record Type

The Record type is the most commonly 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;
};

The code is self-explanatory. Combined with the prerequisites:

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

// The above code 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 in daily development, hence this record.