Generics
Tipuri cu parametri, constrângeri cu extends, keyof și T[K].
Actualizat
Ce sunt generics
Generics sunt tipuri cu parametri. Așa cum o funcție primește valori ca parametri, un generic primește tipuri ca parametri.
Problema pe care o rezolvă:
function first(arr: any[]): any { return arr[0] }
const n = first([1, 2]) // any — ai pierdut informația că e number
function first<T>(arr: T[]): T | undefined { return arr[0] }
const m = first([1, 2]) // number ✓
const s = first(['a']) // string ✓T e un parametru de tip — un loc gol completat automat de TS din argumente. Funcția rămâne una singură, dar tipul rezultatului urmează tipul inputului.
Le folosești deja
const ids: Array<number> = [] // = number[]
const users = new Map<string, User>()
const [count, setCount] = useState<number>(0)
const res: Promise<User> = getUser()Constrângeri cu extends
Uneori T nu poate fi chiar orice — trebuie să aibă ceva anume:
function longest<T extends { length: number }>(a: T, b: T): T {
return a.length >= b.length ? a : b
}
longest('abc', 'de') // ✓ string are length
longest([1, 2], [3]) // ✓ array are length
longest(10, 20) // ✗ number nu are lengthkeyof și acces după cheie
function pluck<T, K extends keyof T>(items: T[], key: K): T[K][] {
return items.map(item => item[key])
}
pluck(users, 'email') // string[]
pluck(users, 'emial') // ✗ typo prinskeyof T = union-ul cheilor lui T; T[K] = tipul valorii de la cheia K.
Tipuri generice
Nu doar funcțiile pot fi generice:
type ApiResponse<T> =
| { ok: true; data: T }
| { ok: false; error: string }
type Paginated<T> = { items: T[]; page: number; total: number }
const res: ApiResponse<Paginated<Product>> = await api('/products')Când folosești generics
| Situație | Generic? |
|---|---|
| funcție care lucrează la fel cu orice tip (first, groupBy, pluck) | da |
| tip „container” (răspuns API, paginare, state de formular) | da |
componentă React reutilizabilă pentru orice tip de item (List<T>, Select<T>) |
da |
funcție care lucrează doar cu User |
nu — scrie User |
Semn că exagerezi: T apare o singură dată în semnătură. Atunci nu e nevoie de generic.
Pe scurt
- Generic = tip cu parametru; păstrează legătura dintre tipul inputului și al outputului.
extendsimpune ce trebuie să aibăT;keyof T+T[K]pentru acces după cheie.- Folosește-le pentru utilitare și containere, nu peste tot.