Back to Blog
TypeScript•
Mastering TypeScript Generics
Level up your TypeScript skills by understanding generics, from basic type parameters to advanced conditional types and utility patterns.
Why Generics Matter
Generics are the backbone of reusable, type-safe code in TypeScript. They let you write functions and types that work with any data type while preserving type information.
Basic Generics
The simplest generic is a type parameter on a function:
function identity<T>(value: T): T {
return value;
}
const str = identity("hello"); // type: string
const num = identity(42); // type: number
Generic Constraints
Use extends to constrain what types are accepted:
interface HasLength {
length: number;
}
function logLength<T extends HasLength>(value: T): void {
console.log(value.length);
}
logLength("hello"); // ✅ strings have length
logLength([1, 2, 3]); // ✅ arrays have length
logLength(42); // ❌ numbers don't have length
Advanced Patterns
Conditional Types
type IsString<T> = T extends string ? "yes" : "no";
type A = IsString<string>; // "yes"
type B = IsString<number>; // "no"
Mapped Types
type Readonly<T> = {
readonly [K in keyof T]: T[K];
};
type Optional<T> = {
[K in keyof T]?: T[K];
};
Template Literal Types
type EventName<T extends string> = `on${Capitalize<T>}`;
type ClickEvent = EventName<"click">; // "onClick"
type FocusEvent = EventName<"focus">; // "onFocus"
Real-World Example: Type-Safe API Client
interface ApiEndpoints {
"/users": { id: string; name: string }[];
"/posts": { id: string; title: string }[];
}
async function fetchApi<T extends keyof ApiEndpoints>(
endpoint: T
): Promise<ApiEndpoints[T]> {
const response = await fetch(endpoint);
return response.json();
}
const users = await fetchApi("/users"); // correctly typed!
Generics might seem intimidating at first, but once you internalize the patterns, they become second nature — and your code becomes dramatically more maintainable.