The satisfies Operator

Validate a value against a type without widening or throwing away its precise inferred type.

satisfies (TypeScript 4.9+) settles an old tension. An annotation like const x: T = ... checks your value but also widens it to T, losing the specific literals. Leaving the annotation off keeps the precise type but skips the check. satisfies gives you both: it verifies the value conforms to a type, then hands you back the narrow inferred type.

type Config = Record<string, string | number>;

const settings = {
  port: 3000,
  host: "localhost",
} satisfies Config;

settings.port.toFixed(0); // OK β€” port is known to be number, not string | number

Had you written const settings: Config, then settings.port would be string | number and .toFixed would error. satisfies keeps the check while preserving the truth.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • A palette object uses satisfies to be validated against a colour map type while retaining tuple types for each colour.
  • A route configuration uses satisfies Record<string, RouteConfig> to catch missing fields without widening the type.
  • A feature flags object uses satisfies to ensure all required flags are present while keeping their literal boolean types.

More examples

satisfies preserves literal types

satisfies validates palette against ColorMap but keeps each value's precise type, so destructuring works without casting.

Example Β· ts
type ColorMap = Record<string, string | [number, number, number]>;

const palette = {
  red:   [255, 0, 0],
  green: [0, 255, 0],
  blue:  'blue',
} satisfies ColorMap;

// palette.red is [number, number, number], not string | [number, number, number]
const [r] = palette.red;

Catching missing required keys

satisfies checks that all required keys are present at the declaration site while keeping the narrowest inferred types.

Example Β· ts
type Routes = { home: string; about: string; contact: string };

const routes = {
  home: '/',
  about: '/about',
  // contact: '/contact',  // Error if uncommented line is removed
} satisfies Routes;       // Error: Property 'contact' is missing

satisfies vs type annotation

Contrasts a type annotation (which widens to string) with satisfies (which keeps the literal type 'verbose').

Example Β· ts
type Config = { debug: boolean; level: string };

// With annotation: level is string
const a: Config = { debug: true, level: 'verbose' };

// With satisfies: level is 'verbose' (literal)
const b = { debug: true, level: 'verbose' } satisfies Config;

// b.level autocompletes as 'verbose', a.level as string

Discussion

  • Be the first to comment on this lesson.
The satisfies Operator β€” TypeScript | SoundsCode