TypeScript Generics and Built-in Utility Types#

In senior-level TypeScript interviews, candidates are often asked:

What are TypeScript Generics, and how do built-in utility types like Omit, Pick, and ReturnType work under the hood?

To answer this, you must demonstrate your understanding of type parameters, mapped types, and conditional types.


1. What Are Generics?#

Generics allow you to write reusable, type-safe components or functions that work with a variety of types rather than a single one. They act as type variables passed to functions, classes, or aliases.

Example of a type-safe API client helper:

TYPESCRIPT
interface ApiResponse<T> {
  data: T;
  status: number;
  success: boolean;
}

interface User {
  id: string;
  name: string;
}

// The generic type User is passed to ApiResponse
const response: ApiResponse<User> = {
  data: { id: "123", name: "Alice" },
  status: 200,
  success: true
};

2. Understanding Built-in Utility Types#

TypeScript provides global utility types to help manipulate object and function types. Let's look at how they are defined internally.

A. Pick<T, K>#

Constructs a type by picking a set of properties K from T.

  • Under the hood:
    TYPESCRIPT
    type Pick<T, K extends keyof T> = {
      [P in K]: T[P];
    };
    

B. Omit<T, K>#

Constructs a type by picking all properties from T and then removing keys in K.

  • Under the hood (uses Exclude):
    TYPESCRIPT
    type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
    

C. ReturnType<T>#

Extracts the return type of a function type T.

  • Under the hood (uses conditional types and the infer keyword):
    TYPESCRIPT
    type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
    

3. Conditional Types & The infer Keyword#

Conditional types allow you to declare types that choose their structure based on a condition:

TYPESCRIPT
SomeType extends OtherType ? TrueType : FalseType

The infer keyword can only be used inside the conditional check of a conditional type. It tells TypeScript to infer a type parameter dynamically at compile time and make it available in the true branch.


Key Takeaways#

  • Generics: Write code that remains flexible while maintaining strict compile-time types.
  • Utility Types: Standard utilities like Pick and Omit use mapped types under the hood to transform object shapes.
  • infer Keyword: Allows you to extract type parameters out of functions, arrays, and promises dynamically.