JS Guide
HomeQuestionsTopicsCompaniesResources
BookmarksSearch

Built for developers preparing for JavaScript, React & TypeScript interviews.

ResourcesQuestionsSupport
HomeQuestionsSearchProgress
HomeTopicstypescriptGenerics
PrevNext
typescript
intermediate
10 min read

Generics

constraints
generics
inference
reusability
type-parameters

Generics let you write functions, classes, and types that work with any type while preserving type safety — the type parameter <T> acts as a variable at the type level, inferred from usage or constrained with extends to require specific shapes.

Key Points

1Type Parameters

Type variables (<T>) capture types from call sites — TypeScript infers them from arguments, preserving type information through function calls.

2Generic Constraints

extends limits what types a generic accepts — T extends { id: number } requires an id property, K extends keyof T constrains to valid property names.

3Type Inference

TypeScript infers generic arguments from usage in most cases — explicit type arguments are only needed when inference fails (empty arrays, ambiguous calls).

4Default Type Parameters

Type parameters can have defaults (T = string) — callers can omit the type argument and get the default, similar to default function parameters.

What You'll Learn

  • Write generic functions that preserve type relationships between inputs and outputs
  • Use constraints (extends) to limit generic type parameters to specific shapes
  • Understand when TypeScript infers generic arguments and when explicit specification is needed
  • Apply common generic patterns like lookup types and factory functions

Deep Dive

Generics are TypeScript's mechanism for creating reusable, type-safe abstractions. Without generics, you'd need to write separate functions for every type or use any and lose type safety.

The Problem Generics Solve

Consider a function that returns the first element of an array:

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

This works but loses type information — first([1, 2, 3]) returns any instead of number. You'd need to cast the result or write separate firstNumber, firstString functions.

With generics:

TSX
function first<T>(arr: T[]): T { return arr[0]; }
const n = first([1, 2, 3]);     // n: number (inferred)
const s = first(['a', 'b']);     // s: string (inferred)

T is a type parameter — a variable that captures the type from the call site. TypeScript infers T from the argument, so you rarely need to specify it explicitly.

Generic Functions

Type parameters are declared in angle brackets before the parameter list:

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

Multiple type parameters (T, U) capture different types in the same function. TypeScript infers all of them from the arguments.

Generic Interfaces and Type Aliases

Generics work on interfaces and types:

TSX
interface ApiResponse<T> { data: T; status: number; error?: string; }
type Result<T, E = Error> = { ok: true; value: T } | { ok: false; error: E };

Default type parameters (E = Error) provide fallback types when the caller doesn't specify them.

Generic Constraints

The extends keyword constrains what types a generic can accept:

JavaScript
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

K extends keyof T means K must be one of T's property names. This enables precise autocomplete and return types — getProperty(user, 'name') returns the specific type of user.name.

Common constraint patterns:

  • T extends object — must be an object type
  • T extends { id: number } — must have a numeric id property
  • T extends (...args: any[]) => any — must be a function
  • T extends readonly any[] — must be an array or tuple

Type Inference with Generics

TypeScript infers generic type arguments from usage, so explicit specification is rarely needed:

JavaScript
const result = map([1, 2, 3], n => n.toString()); // inferred: map<number, string>

Explicit type arguments are needed when inference fails or when you want a more specific type: useState<string[]>([]) because TypeScript would infer never[] from an empty array.

Generic Classes

TSX
class Stack<T> {
  private items: T[] = [];
  push(item: T): void { this.items.push(item); }
  pop(): T | undefined { return this.items.pop(); }
}
const stack = new Stack<number>();

The type parameter applies to all methods and properties in the class.

Common Generic Patterns

  • Identity function: <T>(x: T): T — preserves the exact type through a transformation
  • Factory pattern: <T>(ctor: new () => T): T — creates instances from constructors
  • Lookup pattern: <T, K extends keyof T>(obj: T, key: K): T[K] — type-safe property access
  • Mapped collections: Map<K, V>, Set<T>, WeakMap<K, V> — parameterized containers

Key Interview Distinction

Generics are type-level variables that capture and preserve type information through transformations. Type parameters are inferred from arguments — explicit specification is rarely needed. Constraints (extends) limit what types are accepted and enable type-safe property access patterns. Use generics when the same logic applies to multiple types and you need to preserve the relationship between input and output types.

Fun Fact

The single-letter convention for generic type parameters (T, U, K, V) comes from Java and C#, which inherited it from academic type theory where T stands for 'Type.' Modern TypeScript style guides increasingly prefer descriptive names (TItem, TResult, TKey) for readability, especially when a function has three or more type parameters.

Learn These First

Basic Types

beginner

Function Types

beginner

Continue Learning

Conditional Types

advanced

Mapped Types

advanced

Utility Types

intermediate

Practice What You Learned

What are generics in TypeScript and how do you use them?
mid
generics
Generics allow creating reusable components that work with multiple types while maintaining type safety. They use type parameters (like <T>) that are specified when the component is used, enabling type inference and constraints.
Previous
Function Types
Next
Interfaces vs Type Aliases
PrevNext