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
/**
* @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();
}jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} /**
* @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);
}jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} /**
* @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'?
}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
assertmodule and many test libraries ship typings withasserts, soassert(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
- TypeScript 3.7: assertion functions · TypeScript release notes
- Narrowing · TypeScript handbook
Last reviewed 20 October 2026.