TypeScript Generics: Basics, Constraints, and Real Patterns

A deep, interview-ready guide to TypeScript generics: why they exist, how inference works, constraints (extends), default generics, and practical examples used in real codebases.

F

Frontend Interview Team

February 08, 2026

~24 min
TypeScript Generics: Basics, Constraints, and Real Patterns

Generics are one of the most valuable TypeScript features.

If you can explain generics clearly, you can handle:

  • reusable utilities
  • typed API clients
  • typed React components

1) What problem do generics solve?

Without generics, functions lose type information.

function first(arr: any[]) {
  return arr[0];
}

This returns any — not helpful.

With generics:

function first<T>(arr: T[]): T | undefined {
  return arr[0];
}
 
const x = first([1, 2, 3]);
// x is number | undefined

Generics preserve the relationship between input and output.


2) Generic inference (interview favorite)

TypeScript often infers T automatically:

function wrap<T>(value: T) {
  return { value };
}
 
const a = wrap('hi');
// T inferred as string

You can also specify:

wrap<number>(123);

3) Constraints: extends

Constraints restrict what types are allowed.

function len<T extends { length: number }>(x: T) {
  return x.length;
}
 
len('hello');
len([1, 2, 3]);
len({ length: 10 });

Now TypeScript knows length exists.


4) Keyof + generics (safe property access)

function getProp<T, K extends keyof T>(obj: T, key: K) {
  return obj[key];
}
 
const user = { id: '1', name: 'Rajesh' };
getProp(user, 'name'); // ok
// getProp(user, 'age'); // error

This is a common “advanced but practical” interview example.


5) Default generic types

type ApiResult<T = unknown> =
  | { ok: true; data: T }
  | { ok: false; error: string };

If caller doesn’t supply T, it defaults to unknown.


6) Common real-world patterns

Pattern A: typed async function

async function fetchJson<T>(url: string): Promise<T> {
  const res = await fetch(url);
  if (!res.ok) throw new Error('bad response');
  return res.json() as Promise<T>;
}

Pattern B: map function with generics

function map<T, U>(arr: T[], fn: (x: T) => U): U[] {
  return arr.map(fn);
}

7) Pitfalls

  1. Overusing generics
  • sometimes a union or overload is clearer.
  1. Using any instead of unknown
  • prefer unknown when you don’t know.
  1. Forgetting constraints
  • causes “property does not exist” errors.

8) Interview Q&A

Q: Why use generics instead of any?

  • preserves type relationships and gives autocomplete.

Q: What does T extends ... mean?

  • constraint: T must satisfy that shape.

Summary

  • Generics keep type information across inputs/outputs.
  • TS infers generics often.
  • Use constraints to safely access properties.
  • Keyof + generics is a powerful safe-access pattern.