Configuration & satisfies

The Course
•
4 min read

An annotation declares the type a variable should be viewed through. satisfies checks that an expression is assignable to a type while retaining its resulting inferred type rather than simply treating the variable as the broad target annotation. It does not validate unknown runtime data.

For a small configuration, this can catch a misspelled field or an invalid value while preserving a specific mode. Read the operator as “this expression must meet this contract.” Context still influences inference; do not assume satisfies freezes every literal or means exactly the same inference in every expression.

Use ordinary annotations when you want an intentionally broad view and satisfies for a literal configuration whose precise shape remains useful. Neither makes an object immutable. as const, introduced with tuples tomorrow, is a separate literal-preservation tool and also does not freeze runtime data.

Keep configuration validation and external input validation separate. A checked literal in your source is different from a JSON value arriving from a server. This lesson is about authoring a known configuration, not trusting an arbitrary one.

Predict, run, and explain

Write the output and trace the important state changes before checking it. Then run the program. Use Check types first; execution is allowed only when the real compiler accepts the source.

Predict, then runTypeScript
type Options = {
  mode: "safe" | "fast";

  limit: number;
};

const options = { mode: "safe", limit: 2 } satisfies Options;

function requireSafe(mode: "safe"): string {
  return mode;
}

console.log(requireSafe(options.mode));
console.log(options.limit);

Enable JavaScript to edit and type-check this example.

Check your prediction
safe
2

Read the compiler error

The configuration is a known literal, but the limit still violates its contract.

Find and fix the type errorTypeScript
type Options = {
  mode: "safe" | "fast";

  limit: number;
};

const options = { mode: "safe", limit: "2" } satisfies Options;

console.log(options);

Enable JavaScript to edit and type-check this example.

Check your diagnosis

Keep limit numeric. satisfies checks compatibility; it is not a conversion operation.

Keep the inferred shape after checking the contract

An annotation and satisfies can both reject an invalid configuration, but they present the value differently to later code. A broad annotation intentionally exposes a broad view. Satisfies checks an expression while retaining its resulting inferred shape and contextual literal choices.

Neither operation freezes the value or validates external JSON. Use these tools for known source literals, then keep runtime decoders for data arriving after compilation. Read the inferred field types as well as whether the first assignment passed.

Keep the inferred shape after checking the contract: traceTypeScript
type Options = {
  mode: "safe" | "fast";

  limit: number;
};

const options = { mode: "safe", limit: 2 } satisfies Options;

function safe(mode: "safe"): string {
  return mode;
}

console.log(safe(options.mode));
options.limit = 3;
console.log(options.limit);

Enable JavaScript to edit and type-check this example.

Check your prediction
safe
3

The mode retains the specific safe choice, while limit remains numeric and writable. Satisfies is not shorthand for making every field a readonly literal.

Keep the inferred shape after checking the contract: contrastTypeScript
type Labels = Record<"loading" | "ready", string>;

const labels = { loading: "Wait", ready: "Done" } satisfies Labels;

console.log(Object.keys(labels).join(","));
console.log(labels.ready.toUpperCase());

Enable JavaScript to edit and type-check this example.

Check your prediction
loading,ready
DONE

The required key set gives coverage and the values remain strings. Removing a required property must fail checking; no runtime generator creates the missing field for you.

Try the rule on new inputs

Try a misspelled key, a missing key and a wrong value type separately. Then compare satisfies with an intentionally broad annotation and describe which later calls can use the retained literal information.

Your turn

Exercise

Configuration & satisfies: practise

Define a Labels type as Record<“loading” | “ready”, string>. Create a literal satisfying it and print Loading and Ready. Leave no required label missing.

Your workspaceTypeScript
// Use satisfies on the object expression rather than an assertion.

Enable JavaScript to edit and type-check this example.

Hint 1: the idea

The closed key union describes the complete label table.

Hint 2: a first step

Place satisfies Labels after the closing object brace.

Show one solution
One possible solutionTypeScript
type Labels = Record<"loading" | "ready", string>;

const labels = { loading: "Loading", ready: "Ready" } satisfies Labels;

console.log(labels.loading);
console.log(labels.ready);

Enable JavaScript to edit and type-check this example.

Loading
Ready

Explain why the implementation meets the stated contract. Which part is enforced by the language or checker, and which part needs behavioral evidence?

Change it and test it

Remove ready and inspect the real diagnostic, then restore it. Try a numeric label. Explain whether a clean satisfies check would inspect values loaded from JSON at runtime.

Was this article helpful?

Your response is saved on this device.