TypeScript Types and Generics

Advanced type operators, mapped types, conditional types, and utility types.

View
StandardDetailedCompact
Export
Copy the compact sheet, download it, or print it.
Download
`D` dense toggle · `C` copy all
## Generics
Generic identity function
function identity<T>(value: T): T {
  return value;
}

# Use a type parameter for reusable function typing.

Generic array helper
function first<T>(items: T[]): T | undefined {
  return items[0];
}

# Write array helpers that preserve element types.

Generic interface
interface ApiResponse<T> {
  data: T;
  error?: string;
}

# Parameterize a reusable interface.

Constrain generic types
function printLength<T extends { length: number }>(value: T) {
  console.log(value.length);
}

# Require a minimum shape for a type parameter.

Constrain a key parameter with `keyof`
function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

# Accept only valid property names for a given object type.

## Type Operators
Use `keyof`
type User = { id: number; name: string };
type UserKeys = keyof User; // "id" | "name"

# Get a union of property names from a type.

Use `typeof` in types
const config = {
  retries: 3,
  cache: true,
};

type Config = typeof config;

# Infer a type from an existing value.

Use indexed access types
type User = { profile: { email: string } };
type Email = User["profile"]["email"];

# Get a nested property type from another type.

Use template literal types
type Method = "GET" | "POST";
type Route = "/users" | "/posts";
type Endpoint = `${Method} ${Route}`;

# Compose string literal types from smaller pieces.

## Mapped and Conditional Types
Simple mapped type
type Flags<T> = {
  [K in keyof T]: boolean;
};

# Create a type by iterating over keys.

Conditional type
type IsString<T> = T extends string ? true : false;

# Choose a type based on another type relationship.

Infer a return type
type GetReturn<T> = T extends (...args: never[]) => infer R ? R : never;

# Use `infer` inside a conditional type.

Discriminated union pattern
type Success = { kind: "success"; data: string };
type Failure = { kind: "error"; message: string };
type Result = Success | Failure;

# Model variant objects with a shared discriminant field.

## Utility Types
Use `Partial<T>`
type User = { id: number; name: string; email: string };
type UserPatch = Partial<User>;

# Make every property optional.

Use `Required<T>`
type User = { id?: number; name?: string };
type CompleteUser = Required<User>;

# Make all properties required.

Use `Pick<T, K>`
type User = { id: number; name: string; email: string };
type PublicUser = Pick<User, "id" | "name">;

# Select a subset of properties.

Use `Omit<T, K>`
type User = { id: number; passwordHash: string; email: string };
type SafeUser = Omit<User, "passwordHash">;

# Remove properties from a type.

Use `Record<K, T>`
type FeatureFlag = "billing" | "search";
const flags: Record<FeatureFlag, boolean> = {
  billing: true,
  search: false,
};

# Type objects whose keys all map to the same value type.

Use `Awaited<T>`
type Result = Awaited<Promise<Promise<string>>>; // string

# Unwrap the resolved type of a promise-like value.

Use `ReturnType<T>`
function createUser() {
  return { id: 1, name: "Ada" };
}

type User = ReturnType<typeof createUser>;

# Extract a function’s return type.

Recommended next

No recommendations yet.