Skip to main content
Practice Problems

The satisfies operator in TypeScript

What is the satisfies Operator?

The satisfies operator (introduced in TypeScript 4.9) lets you validate that a value conforms to a type while preserving its narrowed (more specific) type β€” unlike type annotation which widens it.


The Problem satisfies Solves

typescript
type Colors = Record<string, string | number[]>; // With type annotation β€” loses specificity const colors: Colors = { red: "#ff0000", green: [0, 255, 0], }; colors.red.toUpperCase(); // ❌ Error: Property 'toUpperCase' does not exist on type 'string | number[]' colors.green.map(x => x); // ❌ Error: same reason // With satisfies β€” keeps narrow types const colors = { red: "#ff0000", green: [0, 255, 0], } satisfies Colors; colors.red.toUpperCase(); // βœ… TypeScript knows it's a string colors.green.map(x => x); // βœ… TypeScript knows it's number[]

How It Works

ApproachValidates type?Preserves narrow type?
const x: Type = valueβœ…βŒ (widened to Type)
const x = value as Type❌ (no real check)❌
const x = value satisfies Typeβœ…βœ…

Practical Use Cases

Configuration Objects

typescript
type Route = { path: string; method: "GET" | "POST" | "PUT" | "DELETE"; handler: string; }; type Routes = Record<string, Route>; const routes = { getUsers: { path: "/api/users", method: "GET", handler: "UserController.getAll", }, createUser: { path: "/api/users", method: "POST", handler: "UserController.create", }, } satisfies Routes; // TypeScript knows exact keys: "getUsers" | "createUser" // And exact method types: "GET", "POST" (not just the union) routes.getUsers.method; // "GET" (not "GET" | "POST" | "PUT" | "DELETE")

Theme Definition

typescript
type Theme = Record<string, string | { light: string; dark: string }>; const theme = { primary: "#007bff", background: { light: "#ffffff", dark: "#1a1a2e" }, text: { light: "#000000", dark: "#e0e0e0" }, } satisfies Theme; // TypeScript preserves the structure theme.primary.toUpperCase(); // βœ… knows it's string theme.background.light; // βœ… knows it's an object with .light

Enum-like Constants

typescript
type StatusCode = 200 | 201 | 400 | 401 | 404 | 500; const STATUS = { OK: 200, CREATED: 201, BAD_REQUEST: 400, UNAUTHORIZED: 401, NOT_FOUND: 404, SERVER_ERROR: 500, } satisfies Record<string, StatusCode>; // STATUS.OK is 200 (literal), not just StatusCode type OkStatus = typeof STATUS.OK; // 200

Combined with as const

typescript
const palette = { red: "#ff0000", green: "#00ff00", blue: "#0000ff", } as const satisfies Record<string, `#${string}`>; // Values are readonly literal types AND validated as hex colors

Important:

Use satisfies when you want to validate that a value matches a type while keeping the more specific type information. It's a best-of-both-worlds approach β€” type safety without losing type narrowing. It's especially useful for configuration objects, theme definitions, and constant maps.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Finished reading?
Practice Problems