Note
Developer Experience
TypeScript's satisfies Operator Is Underrated
A type annotation validates a value but widens it. The satisfies operator validates without widening — so you keep the exact type you actually wrote.

Reaching for a type annotation to check an object is the reflex, and it quietly costs you information. Annotating with : Record<string, Color> confirms the shape is right, but it also widens every value to Color. The compiler forgets that brand was specifically an RGB tuple, so indexing into it becomes an error. You asked for a check and got a downgrade.
The satisfies operator, added in TypeScript 4.9, separates those two jobs. It verifies the value conforms to a type without changing the value’s inferred type. You get the guardrail and keep the precision.
type RGB = [number, number, number];type Color = RGB | string;
const palette = { brand: [37, 99, 235], danger: "#dc2626",} satisfies Record<string, Color>;
palette.brand[0].toFixed(0); // ✓ brand is still RGB, not Colorpalette.danger.toUpperCase(); // ✓ danger is still stringpalette.accent; // ✗ compile error: property does not existWith an annotation, palette.brand[0] would fail — Color is not indexable — and palette.accent would silently be allowed, because Record<string, Color> promises arbitrary keys. satisfies gives you the opposite and correct pair: the values keep their narrow inferred types, so brand[0] type-checks, while the object is still validated against the constraint, so a typo like accent is caught.
The rule that makes it stick: an annotation constrains and widens; satisfies constrains and preserves. Use it anywhere you write a literal that must match a contract but whose exact shape you still want the compiler to remember — config maps, route tables, style tokens, discriminated-union registries. It is the difference between telling the compiler what a value is and asking it to check what you wrote.
// continue exploring