type RouteConfig = Record<string, { path: string; protected: boolean }>;
// 1. Explicit annotation (pierdem specificul cheilor)
const routesExplicit: RouteConfig = {
home: { path: "/", protected: false },
};
// routesExplicit.home.path -> Eroare TS (nu stie de 'home', doar de string generic)
// 2. Satisfies operator (pastram tipul exact)
const routesSatisfies = {
home: { path: "/", protected: false },
} satisfies RouteConfig;
// Aici functioneaza perfect autocompletion-ul pentru 'home'!
console.log(routesSatisfies.home.path);Salutare! Zilele trecute curățam un codebase măricel la un proiect cu vreo 8k useri activi și m-am lovit iar de veșnica dilemă din TypeScript: cum definim obiectele de configurare fără să pierdem din strictețe? Ani de zile am mers pe adnotări explicite (const x: Type) sau, când ne grăbeam, pe type assertions (as Type). De când a apărut satisfies în TS 4.9, lucrurile s-au schimbat masiv.
Am pățit de prea multe ori să repar bug-uri apărute din cauza unui as pus la repezeală. Hai să vedem patru cazuri concrete de utilizare și cum facem alegerea corectă.
Caz 1: Când vrei validare, dar fără pierderea tipurilor specifice (Type Widening)
Să zicem că ai un obiect de configurare pentru rutele din aplicație. Dacă folosești adnotarea explicită, TypeScript va „lărgi” tipurile. De exemplu, o cheie specifică devine un simplu string, iar tu pierzi autocompletion-ul în IDE.
Dacă folosești satisfies, compilatorul verifică dacă obiectul respectă tipul cerut, dar păstrează tipurile literale exacte pe care le-ai definit. Astfel, când folosești obiectul mai târziu, IDE-ul știe exact ce chei există acolo, fără să le transforme în string generic.
Caz 2: De ce as-ul este o minciună periculoasă
Am avut un caz în producție acum doi ani unde am luat un crash urât în runtime. Un coleg scrisese const user = {} as User. TypeScript a tăcut mâlc, crezând că acel obiect chiar are toate proprietățile unui User. În realitate, era gol, iar când am apelat user.profile.id, aplicația a crăpat.
Regula mea e simplă: folosește as DOAR când știi sigur ceva ce compilatorul nu are cum să deducă (de exemplu, când preiei un element din DOM și știi tipul lui exact). În rest, as trebuie evitat. satisfies nu te lasă să minți; dacă obiectul tău nu are proprietățile necesare, codul nu va compila.
Caz 3: Combo-ul perfect cu as const
Când vrei ca un obiect să fie complet imutabil (read-only) și să aibă tipuri literale exacte, combini as const cu satisfies.
as const îi spune compilatorului că valorile nu se vor schimba niciodată, iar satisfies verifică dacă acele valori respectă structura dorită de tine. Este cel mai sigur mod de a scrie fișiere de configurare sau constante globale în aplicație.
Caz 4: Când rămânem la adnotările explicite?
Nu aruncați încă adnotările explicite la gunoi. Ele sunt sfinte la granița dintre module sau când scrii API-uri publice.
Dacă scrii o funcție dintr-un pachet npm sau dintr-un modul comun, vrei un contract clar. Adnotarea explicită pe valoarea returnată asigură că, dacă modifici ceva în interiorul funcției, compilatorul te va avertiza imediat dacă ai încălcat contractul public. Cu satisfies, tipul returnat ar fi dedus automat și s-ar putea schimba subtil fără ca tu să îți dai seama, stricând codul celor care îți folosesc funcția.
Trade-off-uri și concluzie
Ca în orice tehnologie, avem un compromis. satisfies este genial pentru DX, dar adaugă zgomot vizual în cod dacă este abuzat peste tot.
Pe scurt: folosește adnotări explicite pentru contracte și API-uri publice, satisfies pentru configurări interne și obiecte literale, și fugi de as pe cât posibil.
Voi ce folosiți cel mai des pentru obiectele de configurare din proiectele voastre?