0Pricing
TypeScript Academy · Lesson

satisfies vs Type Annotation

Keep literal inference while still validating shape.

satisfies vs Type Annotation is a free TypeScript Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the TypeScript Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

The Annotation Pattern

The classic pattern const config: Type = {...} validates the object but the variable type becomes Type, widening any literals inside.

type Config = { mode: string; level: number };
const config: Config = { mode: "dark", level: 5 };
// config.mode has type string
console.log(config.mode);

What Widening Looks Like

With the annotation, config.mode is string. You cannot assign it to a variable expecting the literal "dark".

type Config = { mode: string };
const config: Config = { mode: "dark" };
// const m: "dark" = config.mode; // Error: string not assignable to "dark"
console.log(config.mode);

The satisfies Pattern

With const config = {...} satisfies Type, the variable keeps its exact inferred type while still being checked against Type.

type Config = { mode: string; level: number };
const config = { mode: "dark", level: 5 } satisfies Config;
// config.mode has type "dark"
console.log(config.mode);

Exact Inference Preserved

Now config.mode is the literal "dark", so it works anywhere the narrow type is required.

type Config = { mode: string };
const config = { mode: "dark" } satisfies Config;
const m: "dark" = config.mode; // OK
console.log(m);

Both Still Validate

Both patterns reject invalid objects. The difference is purely in the resulting variable type, not in whether validation happens.

type Config = { level: number };
// const a: Config = { level: "x" }; // Error
// const b = { level: "x" } satisfies Config; // Error
const ok = { level: 3 } satisfies Config;
console.log(ok.level);

Extra Properties Are Caught

Like annotations, satisfies flags excess properties that are not in the target type, helping catch typos in keys.

type Config = { mode: string };
// const c = { mode: "dark", extar: true } satisfies Config; // Error: extar
const c = { mode: "dark" } satisfies Config;
console.log(c.mode);

Preserving Tuple-ness

satisfies also helps arrays keep tuple-like precision when combined with as const, while still validating element types.

type Nums = readonly number[];
const xs = [1, 2, 3] as const satisfies Nums;
// xs is a readonly tuple [1, 2, 3], validated as numbers
console.log(xs.length);

Annotation Widens Union Members

If a field is a union like "a" | "b", an annotation typed as the union keeps it the union, but a wider field type widens it. satisfies pins the exact member.

type Config = { tier: string };
const withAnn: Config = { tier: "pro" };       // tier: string
const withSat = { tier: "pro" } satisfies Config; // tier: "pro"
console.log(withAnn.tier, withSat.tier);

Keeping Autocomplete on Reads

Because satisfies preserves literal keys and values, editors can autocomplete based on the exact object, not the wider declared type.

type Theme = Record<string, string>;
const theme = { bg: "black", fg: "white" } satisfies Theme;
// theme.<autocomplete shows bg and fg>
console.log(theme.bg, theme.fg);

Choosing Between Them

Use a plain annotation when you genuinely want the wider type. Use satisfies when you want validation but also need the precise inferred shape afterward.

type Config = { mode: string };
// Want wide type for reassignment flexibility -> annotation
let a: Config = { mode: "dark" };
// Want exact literals for later indexing -> satisfies
const b = { mode: "dark" } satisfies Config;
console.log(a.mode, b.mode);

A Side-by-Side Summary

Annotation widens; satisfies preserves. Both validate. For immutable configs you read from, satisfies is usually the better default.

type C = { color: string; size: number };
const widened: C = { color: "red", size: 1 };
const exact = { color: "red", size: 1 } satisfies C;
console.log(widened.color, exact.color);

Quick Check: satisfies vs Annotation

Test your understanding of the difference.

Recap: satisfies vs Type Annotation

A type annotation validates but widens literals to their base types. The satisfies operator validates and keeps exact inference, preserving literal values, keys, and tuple precision.

type C = { mode: string };
const c = { mode: "dark" } satisfies C;
const exact: "dark" = c.mode;
console.log(exact);

Frequently asked questions

Is the “satisfies vs Type Annotation” lesson free?

Yes — the full text of “satisfies vs Type Annotation” is free to read here on the web, and the TypeScript Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the TypeScript Academy course, upgrade to CoddyKit PRO.

What will I learn in “satisfies vs Type Annotation”?

Keep literal inference while still validating shape. You practise TypeScript Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start TypeScript Academy?

No prior experience is required. TypeScript Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “satisfies vs Type Annotation” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this TypeScript Academy lesson?

Yes. Every TypeScript Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Why satisfies Exists
  2. satisfies vs Type Annotation
  3. satisfies vs as Assertion
  4. Practical satisfies Patterns
← Back to TypeScript Academy