type ColorConfig = Record<string, string | [number, number, number]>;
// 1. satisfies: validează tipul, dar știe valoarea exactă
const palette = {
primary: "#1e40af",
rgbBase: [30, 64, 175],
} satisfies ColorConfig;
palette.primary.toUpperCase(); // OK! TS știe că e string, nu tuplu
// 2. as: minte compilatorul (zero protecție dacă greșești)
const badPalette = { primary: true } as unknown as ColorConfig;Toți am folosit TypeScript ca pe un linter glorificat măcar o dată, mai ales când ardea un release. Anul trecut, la un proiect cu vreo 40k linii de cod, am stat două zile să depanez un bug apărut dintr-un as SomeType aruncat la repezeală într-un handler de evenimente.
Diferențele dintre adnotarea clasică (: Type), type casting (as Type) și operatorul satisfies introdus în 4.9 nu sunt doar detalii de sintaxă. Îți dictează direct cât de sigur e codul tău când îl modifici peste 6 luni.
1. Când folosești adnotarea explicită (: Type)
Adnotarea clasică e bună când vrei un contract strict de intrare sau ieșire. O folosesc aproape exclusiv pe semnăturile funcțiilor — parametri și return types.
Trade-off-ul e că forțează type widening. Dacă declari const config: Record<string, string | number>, TypeScript uită ce tip specific are fiecare proprietate. Dacă apelezi .toLowerCase() pe o proprietate despre care știi sigur că e string în cod, compiler-ul o să urle că poate fi și number. E excelentă pentru contracte API, dar proastă pentru dicționare de configurare sau teme UI.
2. Când folosești satisfies
Operatorul satisfies rezolvă fix problema widening-ului. Validează că obiectul respectă un contract (o interfață sau un type), dar păstrează tipul inferat literal al proprietăților.
Cazul clasic: obiecte de config, teme de culori sau scheme de rute. Vrei să te asiguri că nu uiți vreo cheie cerută de o interfață, dar vrei ca IDE-ul să știe exact că colors.primary e string-ul #0055ff, nu un string generic. Dacă schimbi o valoare, primești eroare de validare la build, dar beneficiezi de autocompletion precis în restul codebase-ului.
3. Când mai are sens as (Type Assertion)
Sincer? În 95% din cazuri, as e o minciună convenabilă pe care i-o spui compiler-ului. as nu validează nimic runtime și maschează erori evidente dacă obiectul nu are de fapt structura promisă.
Singurul loc unde îl mai las în code review este la granița cu medii non-TS pe care nu le controlezi: elemente din DOM (document.getElementById(...) as HTMLInputElement) sau când consumi un payload dintr-un SDK legacy fără tipuri corecte. Dacă te trezești scriind as pe date generate intern în aplicație, de cele mai multe ori ai o problemă de modelare a tipurilor, nu o limitare a limbajului.
4. Combinația as const satisfies Type
Ce faci când vrei și validare structurală, dar și imutabilitate totală cu tipuri literale? Le combini.
satisfies singur nu face proprietățile readonly. Dacă vrei ca o listă de roluri sau o hartă de permisiuni să fie read-only până în măduva oaselor, aplici as const pentru înghețarea valorilor literale și satisfies Type pentru a garanta că respectă schema globală a sistemului.
Merge brici pentru setări de securitate sau tabele de mapping care nu trebuie atinse în timpul execuției.
Ghidul scurt de decizie
- Semnături de funcții și API responses: folosește
: Type. - Obiecte locale, config-uri, rute, teme: folosește
satisfies Type. - Structuri imutabile de referință: folosește
as const satisfies Type. - Elemente DOM sau JSON-uri fără tip de la un server vechi: folosește
as Type(dar ideal combinat cu Zod).
Voi mai aveți vreun scenariu legitim pentru as în cod nou scris de la zero?