Use satisfies when you want the compiler to check a value against a type but keep the narrower type it inferred.
type Config = { port: number; host: string; mode: "dev" | "prod" };
const config = { port: 3030, host: "localhost", mode: "dev" } satisfies Config;
config.mode; // "dev", not "dev" | "prod"
config.port; // 3030 in editor hovers, number after any widening context
With an annotation the check is the same but the type becomes Config, so config.mode is the full union and a switch on it has to handle "prod" too.
const config: Config = { port: 3030, host: "localhost", mode: "dev" };
config.mode; // "dev" | "prod"
When to use which
satisfies: a lookup table, a config object, a route map. You want a typo in a key caught, and you wantObject.keysor a property access to stay as narrow as what you wrote.- Annotation: a value that other code will assign to, or that must be exactly the declared type because it crosses a boundary (a function parameter, a returned API shape).
Gotchas
satisfiesdoesn’t freeze anything. Addas constif you also need the object readonly and every string a literal:{ ... } as const satisfies Config.- Excess property checks still run, so an extra key is an error, the same as with an annotation.
- Function return types can’t use it directly. Annotate the return type, or write
return {...} satisfies Tinside the body. - Needs TypeScript 4.9. On older compilers the keyword is a syntax error.