Skip to content

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.

Rajesh DhimanMarch 01, 20262 min read
On this page

What you’ll learn

  • Why as const is often not enough
  • How satisfies enforces 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 (path must 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 SomeType to “force” a config (hides real errors)
  • Overusing as const everywhere instead of using satisfies strategically

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

  1. Q: How is satisfies different from a type annotation?

    • A: Annotation sets the variable’s type (often widening). satisfies only checks compatibility and keeps narrow inference.
  2. Q: When is it most useful?

    • A: Config/lookup objects where you want both validation and literal types.

Quick recap

  • satisfies validates shape but preserves literals.
  • It’s perfect for route tables/config.
  • Prefer it over casts for safer, cleaner code.
Companion Book

Looking for structured, offline interview prep?

Free online lessons • Portable Amazon Kindle / Paperback

Frontend Interview Guide (2025 Edition) cover
Recommended for React & Frontend Rounds

Frontend Interview Guide (2025 Edition)

By Rajesh Dhiman

Comprehensive preparation covering React internals, Web Performance, CSS architecture, and system design questions.

View on Amazon ↗Kindle & Paperback
JavaScript Interview Guide cover
Recommended for Core JS Rounds

JavaScript Interview Guide

By Rajesh Dhiman

Deep dive into the Event Loop, microtask draining, closures, prototypal inheritance, and asynchronous execution patterns.

View on Amazon ↗Kindle & Paperback

Note: All lessons on Frontend Interview remain completely free to read online. As an Amazon Associate, we may earn from qualifying purchases.

RD

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.