TypeScript Generics Without the Headache
A practical guide to writing reusable, type-safe functions using generics — without over-abstracting.
Generics let you write one function that works with many types without losing type safety.
Start simple
A generic is a placeholder for a type you don’t know yet.
function first<T>(arr: T[]): T | undefined {
return arr[0];
}
first([1, 2, 3]); // number | undefined
first(['a', 'b']); // string | undefined
Constrain when needed
Use extends to restrict what types are allowed.
function getLength<T extends { length: number }>(value: T): number {
return value.length;
}
getLength('hello'); // 5
getLength([1, 2, 3]); // 3
Generic interfaces
interface ApiResponse<T> {
data: T;
status: number;
error?: string;
}
type UserResponse = ApiResponse<User>;
type PostsResponse = ApiResponse<Post[]>;
Default type parameters
interface Paginated<T, Meta = Record<string, unknown>> {
items: T[];
total: number;
meta: Meta;
}
When not to use generics
If a function only works with one type, skip the generic. If you need any to make the generic work, the abstraction is wrong. Use concrete types until two or more callers need the same shape.
// over-engineered
function identity<T>(x: T): T { return x; }
// just use the type
function greet(name: string): string { return `Hello, ${name}`; }Keep reading
Related posts
Writing Clean Functions in JavaScript
Small, focused functions make code easier to test, read, and maintain without over-engineering.
Mastering Array Methods in Modern JavaScript
map, filter, reduce, and friends — when to use each and how to compose them without losing readability.
K3s Single Node: From Zero to Publicly Accessible
Set up k3s on a single node, deploy an app, configure Ingress, DNS, and TLS — everything needed to expose a service to the internet.