Skip to content

Generics Deep Dive

Generics let you write one reusable function or class that works with many types while still preserving type safety.


function identity<T>(value: T): T {
return value;
}

Meaning:

  • input type is T
  • return type is also T

Type is preserved exactly.


function pair<T, U>(first: T, second: U): [T, U] {
return [first, second];
}

Use this when values are different types.


function logLength<T extends { length: number }>(value: T): void {
console.log(value.length);
}

Now T must have a length property.


class Box<T> {
value: T;
constructor(value: T) {
this.value = value;
}
}
const numberBox = new Box<number>(123);
const stringBox = new Box<string>("hello");

type ApiSuccess<T> = { status: "success"; data: T };
type ApiError = { status: "error"; message: string };
type ApiResponse<T> = ApiSuccess<T> | ApiError;
async function fetchData<T>(url: string): Promise<ApiResponse<T>> {
const response = await fetch(url);
if (!response.ok) {
return { status: "error", message: "Request failed" };
}
const data = (await response.json()) as T;
return { status: "success", data };
}
graph LR A[Generic Function] --> B[Input Type T] B --> C[Reusable Logic] C --> D[Return with Same T]