Unul dintre marile avantaje ale TypeScript față de alte sisteme de tipuri este expresivitatea motorului generic. În aplicații enterprise și biblioteci open-source, generics nu înseamnă doar Array<T> sau Promise<T>, ci posibilitatea de a construi meta-tipuri declarative care calculează automat semnăturile interfețelor, validează căi de obiecte și reflectă reguli de business direct în faza de compilare.
// Tipul nativ 'Readonly<T>' îngheață doar proprietățile de la primul nivel.
// Un DeepReadonly recursiv transformă orice structură arborescentă într-una imuabilă:
type DeepReadonly<T> = T extends Function | boolean | number | string | symbol | null | undefined
? T
: T extends Array<infer U>
? ReadonlyArray<DeepReadonly<U>>
: T extends object
? { readonly [K in keyof T]: DeepReadonly<T[K]> }
: T;
interface SetariSistem {
tema: { culori: { primar: string; secundar: string } };
moduleActive: string[];
}
const config: DeepReadonly<SetariSistem> = {
tema: { culori: { primar: '#007acc', secundar: '#ffffff' } },
moduleActive: ['auth', 'billing']
};
// config.tema.culori.primar = '#000000';
// EROARE DE COMPILARE: Cannot assign to 'primar' because it is a read-only property!
Tipuri Recursive și Căi de Acces Dot-Notation (PathKeys)
Un tipar foarte căutat în formulare și sisteme de validare (cum ar fi React Hook Form sau Formik) este validarea la compilare a cheilor imbricate de forma "utilizator.adresa.oras":
type PathKeys<T> = T extends object
? {
[K in keyof T]: K extends string
? T[K] extends Array<any>
? `${K}`
: T[K] extends object
? `${K}` | `${K}.${PathKeys<T[K]>}`
: `${K}`
: never;
}[keyof T]
: never;
interface UtilizatorComplet {
id: number;
profil: {
nume: string;
adresa: { oras: string; strada: string };
};
}
// Căile valide sunt calculate automat:
type CaiValide = PathKeys<UtilizatorComplet>;
// CaiValide = "id" | "profil" | "profil.nume" | "profil.adresa" | "profil.adresa.oras" | "profil.adresa.strada"
function getValoare<T, P extends PathKeys<T>>(obiect: T, cale: P) {
// Implementare sigură la rulare
}
// getValoare(user, "profil.adresa.oras"); // VALID cu autocompletare în IDE!
// getValoare(user, "profil.adresa.codPostal"); // EROARE DE COMPILARE: Argument '"profil.adresa.codPostal"' invalid!
Optimizarea Recursivității: Tail-Call Elimination în tsc
Începând cu TypeScript 4.5, compilatorul implementează optimizarea recursivității pe coadă (Tail-Recursion Elimination) pentru tipurile condiționale. Dacă scrieți tipuri recursive unde apelul recursiv este plasat direct ca rezultat final al condiției, TypeScript poate procesa până la 1000 de niveluri de recursivitate (față de limita anterioară de doar 50 de niveluri).
Capcana Genericității Premature: Când NU trebuie folosit Generic?
- Dacă parametrul de tip este folosit o singură dată: O funcție de forma
function proceseaza<T extends string>(text: T): voideste o complicație inutilă. Scrieți simplu:function proceseaza(text: string): void. - Dacă valoarea de retur nu depinde de tipul argumentului: Generics au scopul de a stabili o legătură matematică între argumente sau între argumente și rezultatul returnat. Dacă legătura nu există, tipul generic doar îngreunează citirea codului și mărește timpii de compilare
tsc.