Type expression

Assertion functions

  • Functions
  • Tested with TypeScript 5.9

An assertion function either returns normally or throws. Declaring it with @returns {asserts value is string} tells TypeScript that if the call returns, value is a string, so the code after the call can use it as one. TypeScript added assertion functions in version 3.7.

@returns {asserts condition} is the general form: after assert(product.price !== undefined, …), TypeScript treats product.price as defined, whatever the check was.

At a glance

Use JSDoc in a .js file TypeScript in a .ts file
Asserts a type /** @returns {asserts value is string} */ (): asserts value is string
Asserts a condition /** @returns {asserts condition} */ (): asserts condition

Examples

assert.js assert.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
/**
 * @param {unknown} value
 * @param {string} name
 * @returns {asserts value is string}
 */
export function assertString(value, name) {
  if (typeof value !== "string") throw new TypeError(`${name} must be a string`);
}

/** @param {unknown} body */
export function readSku(body) {
  assertString(body, "sku");
  return body.toUpperCase();
}
export function assertString(value: unknown, name: string): asserts value is string {
  if (typeof value !== "string") throw new TypeError(`${name} must be a string`);
}

export function readSku(body: unknown) {
  assertString(body, "sku");
  return body.toUpperCase();
}
An assertion function narrows the rest of the scope.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}
assert.js 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
/**
 * @param {unknown} condition
 * @param {string} message
 * @returns {asserts condition}
 */
export function assert(condition, message) {
  if (!condition) throw new Error(message);
}

/** @param {{ sku: string, price?: number }} product */
export function priceOf(product) {
  assert(product.price !== undefined, `${product.sku} has no price`);
  return product.price.toFixed(2);
}
asserts condition, for any check.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}
assert.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: assert.js(13,19): error TS2551: Property 'toFixed' does not exist on type 'string'. Did you mean 'fixed'? 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. assert.js(13,19): error TS2551: Property 'toFixed' does not exist on type 'string'. Did you mean 'fixed'? 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. assert.js(13,19): error TS2551: Property 'toFixed' does not exist on type 'string'. Did you mean 'fixed'? checked 21 October 2026
/**
 * @param {unknown} value
 * @returns {asserts value is string}
 */
function assertString(value) {
  if (typeof value !== "string") throw new TypeError("not a string");
}

/** @param {unknown} quantity */
export function readQuantity(quantity) {
  assertString(quantity);
  return quantity.toFixed(0);error TS2551: Property 'toFixed' does not exist on type 'string'. Did you mean 'fixed'?
}
After the assertion, the value has the asserted type.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}

Predicate or assertion?

A type predicate (value is string) returns a boolean and narrows inside an if. An assertion function throws instead and narrows everything after the call, which reads better at the top of a function that validates its input, as in the first example.

Rules TypeScript applies

TypeScript needs to know the function is an assertion before it narrows, so the function must have an explicit type: a JSDoc @returns {asserts …} on a declaration or on the function itself, or an @type with an asserting function type on the variable that holds it. The examples on this page use declarations.

The narrowing is real: after assertString(quantity), quantity is a string, so quantity.toFixed(0) is an error (TS2551), as the third example shows.

Gotchas

  • An assertion function's own return type is void; it cannot also return a value.
  • Node's assert module and many test libraries ship typings with asserts, so assert(x) from them narrows the same way.

Questions

How do I write an assertion function in JavaScript with JSDoc?

Write a function that throws when the check fails, and give it @returns {asserts value is T} (or @returns {asserts condition} for a boolean condition parameter).

Sources

Last reviewed 20 October 2026.