JSDoc tag

@throws

  • Documentation only
  • Tested with TypeScript 5.9
  • Alias @exception

@throws {ErrorType} description (or @exception) tells readers what a function can throw and when. TypeScript 5.9 parses the type in braces for editor features, so go to definition works on it, but it checks nothing: not what the function throws, not whether callers catch it, and not even whether the type exists.

TypeScript has no checked exceptions in .js or .ts files. With strict, the variable in a catch clause is unknown whatever any @throws says, so narrow it with instanceof before reading .message.

At a glance

Use JSDoc in a .js file TypeScript in a .ts file
Documenting an error /** @throws {RangeError} when the quantity is not positive */ /** @throws {RangeError} when the quantity is not positive */
Handling it catch (error) { if (error instanceof RangeError) … } catch (error) { if (error instanceof RangeError) … }

Examples

parse.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 {string} text
 * @returns {number}
 * @throws {RangeError} when the quantity is not a positive integer
 */
export function parseQuantity(text) {
  const n = Number(text);
  // A TypeError, not the RangeError promised above: tsc does not compare them.
  if (!Number.isInteger(n) || n < 1) throw new TypeError(`Bad quantity: ${text}`);
  return n;
}

// Callers are not made to catch it either.
parseQuantity("3");
@throws is documentation: nothing checks what is thrown or caught.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}
parse.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: parse.js(15,16): error TS18046: 'error' is of type 'unknown'. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. parse.js(15,16): error TS18046: 'error' is of type 'unknown'. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. parse.js(15,16): error TS18046: 'error' is of type 'unknown'. checked 21 October 2026
/**
 * @param {string} text
 * @throws {RangeError}
 */
export function parseQuantity(text) {
  const n = Number(text);
  if (!Number.isInteger(n) || n < 1) throw new RangeError(`Bad quantity: ${text}`);
  return n;
}

try {
  parseQuantity("zero");
} catch (error) {
  console.warn(error.message);error TS18046: 'error' is of type 'unknown'.
}
A caught error is unknown, whatever @throws says.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}
parse.js parse.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 {string} text
 * @throws {RangeError}
 */
export function parseQuantity(text) {
  const n = Number(text);
  if (!Number.isInteger(n) || n < 1) throw new RangeError(`Bad quantity: ${text}`);
  return n;
}

try {
  parseQuantity("zero");
} catch (error) {
  if (error instanceof RangeError) console.warn(error.message);
  else throw error;
}
export function parseQuantity(text: string) {
  const n = Number(text);
  if (!Number.isInteger(n) || n < 1) throw new RangeError(`Bad quantity: ${text}`);
  return n;
}

try {
  parseQuantity("zero");
} catch (error) {
  if (error instanceof RangeError) console.warn(error.message);
  else throw error;
}
Narrow the caught error before using it.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}

How we tested it

The first example promises a RangeError and throws a TypeError; tsc reports nothing, and the caller is not made to catch it. In a separate test, @throws {NoSuchError}, naming a type that does not exist, produced no error either. TypeScript's language service does resolve the type for go to definition, which is why we list the tag as documentation rather than as ignored.

Catching errors

strict includes useUnknownInCatchVariables, so catch (error) gives error the type unknown. Reading error.message directly is TS18046, as the second example shows. error instanceof RangeError narrows it, and rethrowing anything else keeps unexpected errors visible.

Gotchas

  • @throws is not inherited by callers. Document it at each public function that lets the error escape.
  • A thrown value can be anything in JavaScript, not only an Error. That is why the catch variable is unknown rather than the documented type.

Questions

Does TypeScript check @throws?

No. TypeScript 5.9 shows the tag in hovers and links its type, but it reports nothing about thrown or caught errors.

Sources

Last reviewed 20 October 2026.