
Quick answer: TypeScript generics use type parameters — a placeholder for a type you supply at the call site. Write it with angle brackets, as in function first<T>(items: T[]): T. Generics let one function or class work with many types while keeping the relationship between input and output intact, which plain any cannot do.The sections below work through TypeScript generics in the order they click: the problem they solve, constraints, generic interfaces and classes, then the point where TypeScript generics add noise instead of safety.
Table of Contents
The problem TypeScript generics solve
Without generics you either duplicate a function per type or fall back to any, which throws away all type information.
// duplicated and untyped — lose the result type
function firstAny(items: any[]): any {
return items[0];
}
const n = firstAny([1, 2, 3]); // n is any — no help
// generic — T is inferred from the argument
function first<T>(items: T[]): T {
return items[0];
}
const m = first([1, 2, 3]); // m is numberThe key benefit is the link between the parameter and the return type. Pass an array of string and you get a string back; pass User[] and you get a User. The compiler infers T in almost every call, so you rarely write the type argument explicitly.
Constraints: limiting what T can be
The extends clause restricts a type parameter to shapes that have certain members.
function byId<T extends { id: number }>(items: T[]): Map<number, T> {
return new Map(items.map(item => [item.id, item]));
}
byId([{ id: 1, name: "A" }]); // T is { id: number; name: string }
// byId([{ name: "A" }]); // error — no id propertyGenerics on interfaces and classes
interface ApiResponse<T> {
data: T;
status: number;
error?: string;
}
async function get<T>(url: string): Promise<ApiResponse<T>> {
const res = await fetch(url);
return { data: (await res.json()) as T, status: res.status };
}
const users = await get<User[]>("/api/users");
users.data[0].name; // fully typedThat ApiResponse<T> pattern is everywhere in real codebases: one envelope shape, many content types.
The HTTP client in our Angular HTTP guide uses exactly this idea when you write http.get<Product[]>(...).
Defaults and multiple parameters
// default type argument
interface Paginated<T, M = { total: number }> {
items: T[];
meta: M;
}
// two independent type parameters
function merge<A, B>(a: A, b: B): A & B {
return { ...a, ...b };
}
const merged = merge({ name: "Ada" }, { role: "engineer" });
// type: { name: string } & { role: string }When to reach for TypeScript generics
- When the type relationship matters — the output type depends on the input type.
- For containers and collections — a Result, a Cache, a Response wrapper.
- When you would otherwise write
any— a generic with a constraint is nearly always better. - Not for a single concrete use — if a function is only ever called with strings, type it as string.
A good check: if you cannot name what T represents in a sentence, the abstraction is probably premature.
Generics should express a real relationship, not decorate a function that only has one caller.
Next: unions and type narrowing. To learn TypeScript properly with a mentor, Ampersand Academy teaches web development one-to-one.
Frequently asked questions
What is a generic in TypeScript?
A type parameter, written in angle brackets, that stands in for a type chosen at the call site. It keeps the relationship between argument and return types instead of falling back to any.
What does extends mean in a generic?
It constrains the type parameter to shapes that satisfy a condition, such as requiring an id property, so the generic body can use that member safely.
Do I always have to write the type argument?
No. TypeScript infers it from the arguments in most calls. You write it explicitly when inference is not possible or you want a specific type.
What is the difference between any and a generic?
any discards type information, so the compiler cannot help you afterward. A generic preserves the relationship between the input and output types and still catches mistakes.
Can interfaces and classes be generic?
Yes. A generic interface or class declares type parameters just like a function, which is how container types such as ApiResponse of T are written.
Last updated on · Written by Dinesh Kumar R

