
TypeScript: l'operatore satisfies, a cosa serve davvero
L'operatore satisfies di TypeScript spiegato con esempi pratici: perché as e le annotazioni esplicite fanno perdere inferenza, e come satisfies risolve il problema senza compromessi.
Quando definisci un oggetto di configurazione in TypeScript ti trovi spesso davanti a un compromesso che sembra inevitabile: o controlli che la forma dell’oggetto sia corretta, o mantieni i tipi letterali più precisi dei singoli valori. Prima di satisfies (TypeScript 4.9), scegliere l’uno significava perdere l’altro.
Il problema: annotazione esplicita vs inferenza
Prendi una palette di colori, dove ogni valore deve essere una stringa esadecimale valida (`#${string}`):
type Palette = Record<string, `#${string}`>;
const colori: Palette = {
primario: "#3366ff",
secondario: "#ff9900",
};
// colori.primario è tipizzato come `#${string}` — non come "#3366ff"
colori.primario.toUpperCase(); // ok, ma nessun autocomplete sul valore esatto
L’annotazione : Palette verifica correttamente la forma (ogni valore deve iniziare con #), ma TypeScript allarga ogni proprietà al tipo dichiarato nel Record. Il risultato: perdi l’informazione che colori.primario vale esattamente "#3366ff", e con essa autocomplete e controlli più stretti su quel valore specifico.
La tentazione: usare as
L’alternativa ovvia è non annotare affatto e lasciare che TypeScript inferisca:
const colori = {
primario: "#3366ff",
secondario: "#ff9900",
} as const;
Qui riottieni i tipi letterali precisi, ma perdi il controllo opposto: nessun errore se scrivi un valore che non rispetta la forma attesa.
const coloriRotti = {
primario: "#3366ff",
secondario: "arancione", // non è un valore esadecimale, ma nessun errore
} as const;
Con as const TypeScript si limita a congelare i tipi che vede, senza validarli contro nessuna forma. as Palette avrebbe lo stesso problema in forma diversa: as dice al compilatore “fidati di me”, non “controlla che questo rispetti la forma X”.
La soluzione: satisfies
satisfies fa esattamente quello che manca a entrambi gli approcci: valida che il valore rispetti un tipo, senza allargarlo a quel tipo.
const colori = {
primario: "#3366ff",
secondario: "#ff9900",
} satisfies Palette;
colori.primario; // tipo: "#3366ff" — letterale, non `#${string}`
E se un valore non rispetta la forma attesa, l’errore torna a comparire — a differenza di as const:
const coloriRotti = {
primario: "#3366ff",
secondario: "arancione",
// ~~~~~~~~~~
// error! Type '"arancione"' is not assignable to type '`#${string}`'.
} satisfies Palette;
Ottieni entrambe le cose: validazione della forma in fase di compilazione, e inferenza del tipo più preciso possibile per ogni valore.
💡 Consiglio
Un caso pratico dove questo conta davvero: un oggetto di configurazione con chiavi note (per cui
vuoi autocomplete preciso, es. config.endpoints.utenti) ma che deve anche rispettare
un’interfaccia comune (es. ogni endpoint deve avere method e path). satisfies EndpointConfig
ti dà entrambe le garanzie nello stesso punto, senza dover scegliere.
Excess property checks: un altro vantaggio silenzioso
satisfies mantiene anche il controllo delle proprietà in eccesso, che con un’annotazione esplicita a volte si perde per via del widening:
interface Opzioni {
timeout: number;
}
function configura(opzioni: Opzioni) {
/* ... */
}
const mieOpzioni = {
timeout: 3000,
retries: 3, // proprietà non prevista da Opzioni
} satisfies Opzioni;
// ~~~~~~~
// error! Object literal may only specify known properties,
// and 'retries' does not exist in type 'Opzioni'.
Lo stesso controllo che avresti passando il letterale direttamente a configura(...), ma applicato al momento della dichiarazione della costante — utile quando vuoi riusare quell’oggetto altrove prima ancora di passarlo a una funzione.
Quando preferire comunque un’interfaccia esplicita
satisfies non sostituisce sempre un’annotazione di tipo classica. Se hai bisogno che una variabile sia trattata come quel tipo ovunque venga usata — ad esempio un valore che può cambiare forma più avanti nel codice, o un parametro di funzione dove vuoi che il chiamante rispetti esattamente l’interfaccia dichiarata, non il tipo più stretto inferito — l’annotazione esplicita resta la scelta giusta. satisfies è per il caso specifico in cui vuoi validare e preservare l’inferenza sullo stesso valore, tipicamente in oggetti di configurazione, mappe di route o costanti che poi consumi altrove sfruttando i loro tipi letterali.
Vale la pena leggere anche l’articolo su NoInfer, un’altra utility introdotta di recente per controllare — nella direzione opposta — come e quando TypeScript deve inferire i generici.

Co-Fondatore & CTO presso PAPION. Senior full-stack engineer specializzato in React, TypeScript, Node.js e sicurezza applicativa.