Basic Docs
typescripttypes

TypeScript Generics

Type parameters, constraints, utility types, and real-world generic patterns.

What Are Generics?

Generics let you write reusable functions, classes, and interfaces that work with any type while still preserving full type safety. Think of them as type-level parameters — just like function parameters accept values, generics accept types.

Basic generic function
// Without generics — loses type information
function first(arr: unknown[]): unknown {
  return arr[0];
}

// With generics — type flows through
function first<T>(arr: T[]): T {
  return arr[0];
}

const num = first([1, 2, 3]);   // number
const str = first(["a", "b"]);  // string
iWhen to reach for generics
Use generics when the same logic applies to multiple types and you want the output type to be derived from the input type. If you find yourself writing nearly identical functions for different types, a generic is the right fix.
Generic Type Flow
1
Input Type
Caller provides T at the call site
2
Constraint Check
T extends validates the bound
3
Transform
Logic operates on T safely
4
Output Type
Return type derived from T

Constraints

The extends keyword narrows what types a generic parameter can accept. This lets you call methods or access properties on the parameter without losing generality.

Constraining type parameters
// T must have a 'length' property
function longest<T extends { length: number }>(a: T, b: T): T {
  return a.length >= b.length ? a : b;
}

longest("hello", "hi");       // "hello"
longest([1, 2, 3], [4, 5]);   // [1, 2, 3]
// longest(1, 2);             // Error: number has no 'length'

// Key constraint — K must be a key of T
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}
Input type T
extends constraint
Safe property access
Typed output

Common Patterns

These four generic containers appear everywhere in TypeScript codebases. Understanding their type signatures makes reading library types much easier.

Array<T>
Ordered list of T. Equivalent to T[]. Prefer T[] in most cases.
Promise<T>
Async value that resolves to T. Composes with Awaited<T> to unwrap.
Record<K, V>
Object with keys of type K and values of type V. K must extend string | number | symbol.
Map<K, V>
Key-value store with O(1) lookup. Keys are compared by identity, not structure.

Built-in Utility Types

TypeScript ships a library of generic utility types that transform existing types. These cover the vast majority of type manipulation needs without any extra dependencies.

Utility TypeWhat It Does
Partial<T>Makes all properties of T optional
Required<T>Makes all properties of T required
Readonly<T>Prevents reassignment of all properties of T
Pick<T, K>Creates a type with only the keys K from T
Omit<T, K>Creates a type without the keys K from T
ReturnType<F>Extracts the return type of a function type F
Awaited<T>Recursively unwraps the resolved value of a Promise<T>
NonNullable<T>Removes null and undefined from T
TypeScript Type Hierarchy
Literal Types
"hello" | 42 | true
Specific Types
string | number | boolean | object
unknown
Safe top type — must narrow before use
any
Escape hatch — disables type checking entirely

Real-World Examples

The most practical use of generics is building typed wrappers around data-fetching and UI components. The pattern below keeps types flowing from the API call all the way to the rendered output with zero casts.

Generic API wrapper + typed React component
// Generic API response wrapper
interface ApiResponse<T> {
  data: T;
  error: string | null;
  status: number;
}

async function fetchJson<T>(url: string): Promise<ApiResponse<T>> {
  const res = await fetch(url);
  const data = await res.json() as T;
  return { data, error: null, status: res.status };
}

// Usage — T is inferred from the return annotation
const { data } = await fetchJson<User[]>("/api/users");
//    ^? User[]

// Generic React component
function List<T extends { id: string | number }>({
  items,
  render,
}: {
  items: T[];
  render: (item: T) => React.ReactNode;
}) {
  return <ul>{items.map((item) => <li key={item.id}>{render(item)}</li>)}</ul>;
}
Built: 4/8/2026, 12:01:11 PM