type Color = 'red' | 'green' | 'blue';
type Theme = Record<Color, string>;
// 1. Adnotare (pierdem specificitatea)
const theme1: Theme = { red: '#ff0000', green: '#00ff00', blue: '#0000ff' };
// theme1.red e doar 'string'
// 2. Satisfies (păstrăm valorile exacte)
const theme2 = {
red: '#ff0000',
green: '#00ff00',
blue: '#0000ff'
} satisfies Theme;
// theme2.red e recunoscut ca valoarea specifică '#ff0000'
// Dacă adăugăm o cheie greșită, TS urlă imediat.Am observat o tendință periculoasă în ultimele luni la review-urile de cod: lumea folosește operatorii de tipare în TypeScript după ureche. Mulți vin din Java sau C# și au instinctul să scrie mereu tipul în stânga, alții s-au obișnuit cu as de pe vremea când TypeScript era mult mai limitat. Adevărul e că, de la versiunea 4.9 încoace, regulile jocului s-au schimbat și mulți scriem cod mai fragil decât e necesar.
Recent, la un proiect unde aveam de gestionat o configurație complexă pentru vreo 12 micro-frontends, am pierdut două ore căutând un bug care nu ar fi trebuit să existe. Totul plecase de la un as pus aiurea care a convins compilatorul că un obiect are niște chei pe care, în realitate, le ștersesem din API.
1. Adnotarea explicită: Safe, dar uneori prea rigidă
Când scrii const user: User = { ... }, îi spui lui TS: „Verifică dacă obiectul ăsta respectă contractul User”. E util la început, dar are o problemă mare: type widening. Dacă ai un tip cu proprietăți opționale sau uniuni, TS va „lărgi” tipul obiectului tău la acea interfață și vei pierde informația specifică pe care o aveai inițial.
Am pățit asta la un sistem de teme (dark/light). Adnotând obiectul cu Record<string, string>, am pierdut auto-complete-ul pentru cheile specifice ca primaryButton. E frustrant să ai tipare și totuși să primești string peste tot în IDE.
2. Operatorul as: Minciuna prin omisiune
Folosesc as doar când chiar nu am de ales, de exemplu la un răspuns de la un API legacy unde n-am chef de validări Zod (greșeala mea, știu). Problema cu as e că e un „type assertion”, nu o verificare. Îi spui compilatorului „Taci, știu eu mai bine”.
La un proiect cu 8k useri activi, am avut un crash în producție pentru că un coleg a folosit as pe un obiect venit dintr-un JSON. Obiectul era parțial gol, dar TypeScript a crezut că e valid. Am învățat atunci lecția: as e pentru teste sau pentru situații extreme, nu pentru business logic de zi cu zi.
3. Operatorul satisfies: Cel mai bun din ambele lumi
Ăsta e game-changer-ul introdus în TS 4.9. Îi spui lui TS: „Verifică dacă obiectul respectă tipul X, dar păstrează inferența cea mai specifică posibilă”.
Dacă ai un obiect cu culori și folosești satisfies, TS te va opri dacă uiți o culoare obligatorie, dar în același timp va ști exact ce string-uri ai folosit ca chei. Nu le transformă într-un string generic. Am economisit cam 30% din timpul de debug la configurări de rute folosind abordarea asta, pentru că IDE-ul îmi zicea exact unde am typo-uri fără să mă oblige să fac cast-uri peste tot.
4. Combo-ul fatal: as const satisfies
Când vrei imutabilitate maximă și validare, ăsta e setup-ul suprem. as const face toate proprietățile readonly și transformă string-urile în literali, iar satisfies se asigură că nu ai uitat nimic din interfață.
Merge de minune pentru obiecte de configurare, mesaje de eroare sau definiții de permisiuni. Trade-off-ul? Codul devine un pic mai dens și s-ar putea ca unii colegi care nu sunt la curent cu ultimele noutăți din TS să se uite ciudat la sintaxă. Dar prefer o întrebare la code review decât un incident la ora 5 după-amiaza.
Voi ce folosiți cel mai des pentru obiectele de configurare? Mai are as loc în codebase-ul vostru în afară de fișierele de test?