Generics in TypeScript
Generics in TypeScript
Section titled “Generics in TypeScript”What are Generics?
Section titled “What are Generics?”Generics allow you to create reusable components that work with any type while maintaining type safety. Instead of working with any, generics capture the type as a parameter.
Analogy: A generic function is like a vending machine that works with any product — the mechanics are the same, but the product type varies.
One Function, Many Types
Section titled “One Function, Many Types”flowchart LR GF[Generic Function<br/>function identity T (arg: T): T] --> C1["identity string ('hello')<br/>T = string → returns string"] GF --> C2["identity number (42)<br/>T = number → returns number"] GF --> C3["identity boolean (true)<br/>T = boolean → returns boolean"]
style GF fill:#7c3aed,color:#fff style C1 fill:#f59e0b,color:#fff style C2 fill:#f59e0b,color:#fff style C3 fill:#f59e0b,color:#fffThink of
Tas a placeholder: you callidentity("hello"), and TypeScript fills inT = stringautomatically. One function body works for any type, and you never lose type information.
Basic Generic Function
Section titled “Basic Generic Function”function identity<T>(arg: T): T { return arg;}
// Type is inferredconst result1 = identity("hello"); // type: stringconst result2 = identity(42); // type: number
// Type can be explicitconst result3 = identity<string>("hello");Generic Constraints
Section titled “Generic Constraints”interface HasLength { length: number;}
function logLength<T extends HasLength>(arg: T): T { console.log(arg.length); return arg;}
logLength("hello"); // OK — string has lengthlogLength([1, 2, 3]); // OK — array has length// logLength(42); // ❌ Error: number has no lengthGeneric Interfaces
Section titled “Generic Interfaces”interface Repository<T> { getById(id: string): Promise<T | null>; getAll(): Promise<T[]>; create(data: Omit<T, "id">): Promise<T>; update(id: string, data: Partial<T>): Promise<T>; delete(id: string): Promise<boolean>;}
// Usage with specific typeinterface User { id: string; name: string; email: string;}
class UserRepository implements Repository<User> { async getById(id: string): Promise<User | null> { // Implementation return null; } // ... other methods}Real Project Example
Section titled “Real Project Example”// Generic API clientclass ApiClient<T> { private baseUrl: string;
constructor(baseUrl: string) { this.baseUrl = baseUrl; }
async get(id: string): Promise<T> { const response = await fetch(`${this.baseUrl}/${id}`); return response.json(); }
async getAll(): Promise<T[]> { const response = await fetch(this.baseUrl); return response.json(); }}
const userClient = new ApiClient<User>("/api/users");const user = await userClient.get("1"); // type: UserInterview Questions
Section titled “Interview Questions”Easy: What is a generic in TypeScript?
Medium: How do generic constraints work with extends?
Hard: How would you create a generic repository pattern?