satisfies: Enforce Shape Without Losing Literal Types
Use the satisfies operator to validate objects (routes, feature flags, configs) while preserving literals for great inference and fewer casts.
On this page
What you’ll learn
- Why
as constis often not enough - How
satisfiesenforces a contract without widening your values - Real patterns: route tables, feature flags, and event maps
30‑second interview answer
satisfies checks that a value conforms to a type, but it keeps the value’s most specific inferred type. That makes it ideal for config objects where you want compile-time validation without losing literal types. Compared to const x: SomeType = ..., satisfies avoids unwanted widening.
The problem: annotation widens your literals
type RouteTable = Record<string, { path: string; auth: "public" | "private" }>;
const routes: RouteTable = {
home: { path: "/", auth: "public" },
settings: { path: "/settings", auth: "private" }
};
routes.home.path; // string (widened)Sometimes you want "/" as a literal type.
satisfies keeps literals while enforcing the contract
type RouteTable = Record<string, { path: `/${string}`; auth: "public" | "private" }>;
const routes = {
home: { path: "/", auth: "public" },
settings: { path: "/settings", auth: "private" }
} satisfies RouteTable;
routes.home.path; // "/" (literal!)You get:
- Contract enforcement (
pathmust start with/) - Literal inference for downstream typing
Pattern: route helpers with perfect inference
type Routes = typeof routes;
type RouteName = keyof Routes;
function linkTo<R extends RouteName>(name: R) {
return routes[name].path;
}
const a = linkTo("home"); // "/"
const b = linkTo("settings"); // "/settings"Pattern: feature flags with safe keys
type Flag = { owner: "growth" | "core"; rollout: 0 | 10 | 50 | 100 };
type FlagMap = Record<string, Flag>;
const flags = {
newNav: { owner: "growth", rollout: 10 },
fasterSearch: { owner: "core", rollout: 50 }
} satisfies FlagMap;
type FlagName = keyof typeof flags;Now FlagName is a safe union: "newNav" | "fasterSearch".
Common mistakes
- Using
as SomeTypeto “force” a config (hides real errors) - Overusing
as consteverywhere instead of usingsatisfiesstrategically
Production rule of thumb
Use satisfies for config objects and lookup tables:
- Routes
- Events
- Permissions
- Feature flags
It gives you strict validation + great inference.
Interview questions
-
Q: How is
satisfiesdifferent from a type annotation?- A: Annotation sets the variable’s type (often widening).
satisfiesonly checks compatibility and keeps narrow inference.
- A: Annotation sets the variable’s type (often widening).
-
Q: When is it most useful?
- A: Config/lookup objects where you want both validation and literal types.
Quick recap
satisfiesvalidates shape but preserves literals.- It’s perfect for route tables/config.
- Prefer it over casts for safer, cleaner code.
Looking for structured, offline interview prep?
Free online lessons • Portable Amazon Kindle / Paperback
Frontend Interview Guide (2025 Edition)
By Rajesh Dhiman
Comprehensive preparation covering React internals, Web Performance, CSS architecture, and system design questions.
JavaScript Interview Guide
By Rajesh Dhiman
Deep dive into the Event Loop, microtask draining, closures, prototypal inheritance, and asynchronous execution patterns.
Note: All lessons on Frontend Interview remain completely free to read online. As an Amazon Associate, we may earn from qualifying purchases.
Written by Rajesh Dhiman
Authored by Rajesh Dhiman and engineered at Eunix Tech. Focused on deep-dive frontend engineering, JavaScript runtime internals, React architecture, and web performance.