2 min read

TypeScript satisfies Operator

Introduced in TypeScript 4.9, the satisfies operator allows you to validate that an expression matches a type, without changing the resulting type of that expression.

1. The Problem: Type Annotation vs. Inference

Traditionally, when you annotate a variable with a type, you lose the specific details of the value you assigned. TypeScript "widens" the type to match the annotation.

type Colors = "red" | "green" | "blue";
type RGB = [number, number, number];

const palette: Record<Colors, string | RGB> = {
    red: [255, 0, 0],
    green: "#00ff00",
    blue: [0, 0, 255]
};

// PROBLEM: TypeScript only knows that 'red' is 'string | RGB'.
// It doesn't remember that we assigned an array specifically to 'red'.

// Error: Property 'map' does not exist on type 'string | RGB'.
// palette.red.map(x => x * 2); 

// Error: Property 'toUpperCase' does not exist on type 'string | RGB'.
// palette.green.toUpperCase();

2. The Solution: satisfies

The satisfies operator checks that the value conforms to the type, but keeps the inferred, specific type of the value.

const palette = {
    red: [255, 0, 0],
    green: "#00ff00",
    blue: [0, 0, 255]
} satisfies Record<Colors, string | RGB>;

// 1. Validation works: If we miss a key or use a wrong type, TS errors.
// const badPalette = { red: "yes" } satisfies Record<Colors, string | RGB>; // Error: missing keys

// 2. Inference is preserved!

// TypeScript knows palette.red is [number, number, number]
palette.red.map(x => x * 2); // OK

// TypeScript knows palette.green is string
palette.green.toUpperCase(); // OK

3. Use Case: Configuration Objects

This is extremely useful for configuration objects where values can be of multiple types (e.g., a single string or an array of strings), and you want to use methods specific to those types later.

type ConnectionConfig = {
    host: string | string[];
    port: number;
};

const config = {
    host: "localhost", // Inferred as string, validated against string | string[]
    port: 8080
} satisfies ConnectionConfig;

// TS knows config.host is a string, so this works:
console.log(config.host.toUpperCase());

Summary: Use satisfies when you want to ensure a value matches a contract (interface/type) but want to retain the most specific type information possible for usage.

programming/javascript/typescript/typescript