Learn how the satisfies operator validates that an object matches a type shape without widening or losing inferred literal types.
Discover how TypeScript infers types automatically and how let versus const declarations shape wide types versus narrow literal types.
TypeScript 4.9 introduced the satisfies operator. It solves a classic TypeScript dilemma: validating that an object conforms to a type shape WITHOUT widening its specific inferred property types.
When you annotate a variable explicitly (const obj: Type = {...}), TypeScript widens object properties to general types, losing exact literal inference:
type Colors = "red" | "green" | "blue";
type RGB = [number, number, number];
type Palette = Record<Colors, string | RGB>;
// Explicit annotation widens properties to 'string | RGB'
const paletteAnnotation: Palette = {
red: [255, 0, 0],
green: "#00ff00",
blue: [0, 0, 255],
};
// Error! paletteAnnotation.green might be an RGB tuple according to the wide type!
// paletteAnnotation.green.toUpperCase();
satisfies SolutionThe satisfies operator validates the schema contract while preserving exact literal inference:
const paletteSatisfies = {
red: [255, 0, 0],
green: "#00ff00",
blue: [0, 0, 255],
} satisfies Palette;
// Success! TypeScript REMEMBERS green is a string!
console.log(paletteSatisfies.green.toUpperCase()); // "00FF00"
// Success! TypeScript REMEMBERS red is a tuple!
console.log(paletteSatisfies.red.map((c) => c / 2));
Explicit Annotation (const p: Palette) ──> Validates Schema AND Widens Inferred Types
Satisfies Operator (const p satisfies)──> Validates Schema AND PRESERVES Exact Types!
satisfies with Type Assertions (as): as bypasses validation and forces a type override. satisfies strictly VALIDATES the object and throws errors if invalid!Use satisfies for configuration objects and theme palettes. Next, let's explore Branded Types and Nominal Typing!