@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
/**
* @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");jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} /**
* @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'.
}jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} /**
* @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;
}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
@throwsis 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 isunknownrather 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
- @throws · JSDoc
- TypeScript 4.4: defaulting to the unknown type in catch variables · TypeScript release notes
- JSDoc Reference · TypeScript handbook
Last reviewed 20 October 2026.