JSDoc tag

@satisfies

  • Checked by TypeScript
  • Since TypeScript 5.0

@satisfies {Type} checks that a value fits Type without changing the value's type. A misspelled or missing property is an error, as with @type, but the variable keeps the exact type TypeScript infers: its own keys, its literal values, its specific property types. TypeScript 5.0 added the tag as the JavaScript form of the satisfies operator from TypeScript 4.9.

That makes it the right tag for configuration objects, route tables, lookup maps and other values whose keys you want both checked and remembered.

At a glance

Use JSDoc in a .js file TypeScript in a .ts file
On a declaration /** @satisfies {Record<string, Route>} */ const routes = { … }; const routes = { … } satisfies Record<string, Route>;
On an expression /** @satisfies {Route} */ ({ path: "/" }) ({ path: "/" }) satisfies Route

Examples

routes.js routes.ts TypeScript 5.9.3 TypeScript 5.9.3, run 21 October 2026: No errors. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. No errors. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. No errors. checked 21 October 2026
/** @typedef {{ path: string, auth?: boolean }} Route */

/** @satisfies {Record<string, Route>} */
export const routes = {
  home: { path: "/" },
  cart: { path: "/cart" },
  account: { path: "/account", auth: true },
};

// The keys stay known: routes.home exists, routes.hmoe would be an error.
routes.home.path;
type Route = { path: string; auth?: boolean };

export const routes = {
  home: { path: "/" },
  cart: { path: "/cart" },
  account: { path: "/account", auth: true },
} satisfies Record<string, Route>;

routes.home.path;
Checking an object with @satisfies while keeping its own type.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}
routes.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: routes.js(7,32): error TS2353: Object literal may only specify known properties, and 'atuh' does not exist in type 'Route'. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. routes.js(7,32): error TS2353: Object literal may only specify known properties, and 'atuh' does not exist in type 'Route'. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. routes.js(7,32): error TS2353: Object literal may only specify known properties, and 'atuh' does not exist in type 'Route'. checked 21 October 2026
/** @typedef {{ path: string, auth?: boolean }} Route */

/** @satisfies {Record<string, Route>} */
export const routes = {
  home: { path: "/" },
  account: { path: "/account", atuh: true },error TS2353: Object literal may only specify known properties, and 'atuh' does not exist in type 'Route'.
};
A misspelled property, caught by @satisfies.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}
routes.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: routes.js(12,9): error TS2339: Property 'hmoe' does not exist on type '{ home: { path: string; }; }'. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. routes.js(12,9): error TS2339: Property 'hmoe' does not exist on type '{ home: { path: string; }; }'. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. routes.js(12,9): error TS2339: Property 'hmoe' does not exist on type '{ home: { path: string; }; }'. checked 21 October 2026
/** @typedef {{ path: string, auth?: boolean }} Route */

/** @type {Record<string, Route>} */
const typed = { home: { path: "/" } };

/** @satisfies {Record<string, Route>} */
const checked = { home: { path: "/" } };

// With @type, any key is allowed, so the typo is not caught.
typed.hmoe;
checked.hmoe;error TS2339: Property 'hmoe' does not exist on type '{ home: { path: string; }; }'.

export { typed, checked };
What @type loses and @satisfies keeps.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}

@satisfies or @type?

@type {Record<string, Route>} makes the variable that type. Every key is then allowed, so typed.hmoe passes even though nothing defines it. @satisfies checks the same thing but leaves the type as { home: … }, so checked.hmoe is an error (TS2339). The third example puts the two side by side.

Use @type when the variable should accept other values of the type later, such as a let that is reassigned. Use @satisfies when the value is fixed and you want TypeScript to remember exactly what it is.

On functions

@satisfies also suits functions that must match a type from a library. Unlike @type, it does not impose the type's return type on the function body, which avoids the TS2355 trap described on the @type page and in the Express handler recipe.

Gotchas

  • The satisfies operator itself is TypeScript syntax; {…} satisfies Route in a .js file is TS8037.
  • @satisfies checks; it does not cast. To change a value's type, use a @type cast with parentheses.

Questions

What does @satisfies do in JSDoc?

It checks the value against the type in braces and reports any mismatch, while the variable keeps the narrower type TypeScript infers from the value itself.

Sources

Last reviewed 20 October 2026.