Ce face generics (<T>)
Un generic este un tip-parametru, scris între paranteze unghiulare: <T>. Așa cum un parametru obișnuit primește o valoare la apel, T primește un tip. function primul<T>(lista: T[]): T | undefined funcționează pentru orice tablou și returnează exact tipul elementelor: pentru string[] dă string, pentru Elev[] dă Elev.
De obicei nu scrii tipul la apel: TypeScript îl deduce din argumente (primul([1, 2]) deduce T = number). Îl poți da și explicit: primul<string>([]). Pot fi mai mulți parametri (<K, V>), iar unul poate avea o valoare implicită (<T = string>).
Generics apar peste tot în bibliotecile standard: Array<T>, Map<K, V>, Promise<T>, Set<T>. Alternativa, any, acceptă tot dar pierde tipul; un generic acceptă tot și îl păstrează. Pentru a cere ca T să aibă anumite proprietăți vezi constrângeri generice.
Exemple
Exemplul 1: Funcție generică
Aceeași funcție returnează number, string sau Elev, după tabloul primit.
function ultimul<T>(lista: T[]): T | undefined {
return lista[lista.length - 1];
}
interface Elev {
nume: string;
}
const n = ultimul([9, 10, 8]); // number | undefined
const o = ultimul(["Iași", "Cluj"]); // string | undefined
const e = ultimul<Elev>([{ nume: "Ana" }, { nume: "Mihai" }]);
console.log(n, o?.toUpperCase(), e?.nume);
console.log(ultimul([]));
Rezultat
8 CLUJ Mihai
undefined
Exemplul 2: Clasă generică
class Stiva<T> {
#elemente: T[] = [];
pune(x: T): void {
this.#elemente.push(x);
}
scoate(): T | undefined {
return this.#elemente.pop();
}
get marime(): number {
return this.#elemente.length;
}
}
const pagini = new Stiva<string>();
pagini.pune("/acasa");
pagini.pune("/invata");
pagini.pune("/invata/typescript");
console.log(pagini.scoate(), pagini.scoate(), pagini.marime);
Rezultat
/invata/typescript /invata 1
Exemplul 3: Tipul se păstrează, deci greșelile se văd
T este number pentru stiva note, deci un text nu poate fi adăugat.
class Stiva<T> {
elemente: T[] = [];
pune(x: T) {
this.elemente.push(x);
}
}
const note = new Stiva<number>();
note.pune(10);
note.pune("nouă");
Eroarea afișată de tsc
exemplu.mts(9,11): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
Greșeli frecvente
- Folosești un generic doar o dată în semnătură (
f<T>(x: T): void). Nu leagă nimic; un tip simplu (unknown) e mai clar. - Scrii
<T>într-o funcție săgeată dintr-un fișier.tsx; acolo este citit ca tag JSX. Scrie<T,>sau<T extends unknown>.
Comenzi înrudite
constrângeri generice (extends): T extends Tip limitează tipurile permise pentru T, ca funcția să poată folosi proprietățile lui Tip.keyof: keyof T dă union-ul numelor de proprietăți ale lui T, de exemplu „nume” | „oras”.funcții cu tipuri: Pui tipuri pe parametrii și pe rezultatul funcțiilor; fiecare apel este verificat la compilare.conditional types: Un tip care alege între două variante după o condiție: T extends U ? X : Y.NoInfer: NoInfer<T> oprește deducerea lui T din acel parametru; T se deduce doar din celelalte argumente.