Generics
Write flexible, reusable code with generics — type parameters for functions and classes.
Generics
Generics let you write reusable components that work with multiple types while keeping type safety.
The Problem
// This loses type info — returns 'any'
const addUID = (obj: object) => {
let uid = Math.floor(Math.random() * 100);
return { ...obj, uid };
};
const result = addUID({ name: "Mario" });
console.log(result.name); // ❌ Error — TS doesn't know about 'name'
Using Generics
const addUID = <T>(obj: T) => {
let uid = Math.floor(Math.random() * 100);
return { ...obj, uid };
};
const result = addUID({ name: "Mario", age: 30 });
console.log(result.name); // ✅ TypeScript knows about 'name'
console.log(result.uid); // ✅ And 'uid'
Constraining Generics
const addUID = <T extends object>(obj: T) => {
return { ...obj, uid: Math.random() };
};
addUID({ name: "Mario" }); // ✅
addUID("hello"); // ❌ Error — string is not an object
// More specific constraint
const addUID = <T extends { name: string }>(obj: T) => {
return { ...obj, uid: Math.random() };
};
Generic Interfaces
interface Resource<T> {
uid: number;
resourceName: string;
data: T;
}
const docOne: Resource<string> = {
uid: 1, resourceName: "person", data: "Mario"
};
const docTwo: Resource<string[]> = {
uid: 2, resourceName: "names", data: ["Mario", "Luigi"]
};
Key Takeaways
- Generics use
<T>as type parameters - They preserve type information while being flexible
- Use
extendsto constrain what types are allowed - Interfaces and classes can also be generic