Generics

Intermediate
TypeScript

Generics carry a type through a function instead of losing it. Familiar from Java, with two differences worth knowing: inference is much stronger, and there is no erasure workaround because there is nothing to work around.

Overview

A generic is a type parameter — a placeholder filled in at each call site so the relationship between input and output survives. Java engineers already have this instinct, and most of it transfers directly. What differs is that TypeScript infers type arguments aggressively, so you rarely write them explicitly, and that constraints use `extends` in a structural rather than nominal sense. The habit worth building is reaching for a generic only when a type genuinely flows through; a generic used once in a signature is usually a disguised `any`.

Carrying a Type Through

Without a generic the type is lost. With one, it survives.

The type flows from argument to return
// Loses the type
function firstAny(arr: any[]): any { return arr[0] }
const n = firstAny([1, 2, 3])       // any — no help downstream

// Keeps it
function first<T>(arr: T[]): T | undefined { return arr[0] }
const m = first([1, 2, 3])          // number | undefined — inferred, no <number> needed

// Two parameters, related
function mapValues<T, U>(obj: Record<string, T>, fn: (v: T) => U): Record<string, U> {
  return Object.fromEntries(
    Object.entries(obj).map(([k, v]) => [k, fn(v)]),
  ) as Record<string, U>
}

// A typed fetch wrapper — the pattern you will actually write
async function api<T>(path: string): Promise<T> {
  const res = await fetch(path)
  if (!res.ok) throw new Error(res.statusText)
  return res.json() as Promise<T>
}
const problems = await api<Problem[]>('/api/problems')

Constraints

extends narrows what T can be, which is what lets you use its members.

extends, keyof, and defaults
// Unconstrained T has no members you can touch
function longest<T extends { length: number }>(a: T, b: T): T {
  return a.length >= b.length ? a : b
}
longest('arrays', 'graphs')        // string
longest([1, 2], [1, 2, 3])         // number[]
longest(1, 2)                      // Error — number has no length

// keyof, for type-safe property access
function pluck<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key]
}
pluck(user, 'name')      // string
pluck(user, 'emial')     // Error — not a key of T

// Defaults
interface Paged<T = unknown> { items: T[]; total: number }

// Where Java says <T extends Comparable<T>>, TypeScript says
// <T extends { compareTo(other: T): number }> — structural, not nominal.

When Not to Use One

A type parameter that appears once is not doing anything.

A type parameter needs to appear twice
// Pointless — T appears once, so it is just 'any' with extra steps
function log<T>(value: T): void { console.log(value) }
function log2(value: unknown): void { console.log(value) }   // same thing, clearer

// Also pointless — the constraint is the whole type
function len<T extends string>(s: T): number { return s.length }
function len2(s: string): number { return s.length }         // identical

// Useful — T connects two positions
function keyBy<T, K extends keyof T>(items: T[], key: K): Map<T[K], T>

// Rule of thumb: a type parameter must appear at least twice —
// once to receive the type, once to use it.

Key Points to Remember

  • 1A generic preserves the relationship between input and output types instead of collapsing to any
  • 2TypeScript infers type arguments from the call site, so explicit <T> is rarely needed
  • 3extends constrains a type parameter, which is what allows you to access members on it
  • 4K extends keyof T is the pattern for type-safe property access by name
  • 5A type parameter appearing only once in a signature is doing nothing — use unknown or the concrete type

Interview Questions

Sign in to ask Aria
1

Why use a generic instead of any for a function that returns an array element?

Easy
2

What does K extends keyof T let you do, and why is it safer than a string parameter?

Medium
3

When is a generic type parameter unnecessary?

Medium

Ask Aria about Generics

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…