JSDoc: documenting and typing JavaScript without leaving the .js

JSDoc describes a function inside a structured comment that editors and TypeScript can read: the useful tags, typing without a compiler, and the limits.
3 min read
Believemy logo

A well-named function still says nothing about the unit of its arguments, about what it hands back when it fails, or about which parameters are optional.

JSDoc puts those answers directly above it, in a comment the editor shows at every call site and that TypeScript knows how to verify.


Definition

JSDoc is a convention for writing JavaScript comments. A block opened with /** and made of tags prefixed by an at sign describes the parameters, the returned value and the types involved. The language ignores it, the tooling does not.

JAVASCRIPT
/**
 * Computes the gross amount of an invoice.
 *
 * @param {number} netAmount The amount before tax, in euros.
 * @param {number} [rate] The tax rate, 0.2 by default.
 * @returns {number} The gross amount, rounded to the cent.
 */
function grossTotal(netAmount, rate = 0.2) {
  return Math.round(netAmount * (1 + rate) * 100) / 100;
}

console.log(grossTotal(19));   // 22.8

The square brackets around rate mark a Default parameter, and therefore an optional argument. The editor repeats these three lines in its tooltip, and completion now knows the nature of every argument.


The everyday tags

TagWhat it describes
@paramOne argument: its type, its name, its role
@returnsThe value handed back, and under what condition
@typeThe type of a variable or a constant
@typedefA named type, reusable across the whole file
@propertyOne field of the type declared just above
@throwsThe Error the function may raise

Six tags cover very nearly every need. The remaining thirty or so mostly serve documentation generators.


Typing a .js file with no compiler

A // @ts-check comment at the top of a file, or the project-wide checkJs option, and the TypeScript checker treats JavaScript exactly like TypeScript, reading the types out of the comments.

JAVASCRIPT
/**
 * @typedef {object} Invoice
 * @property {number} id
 * @property {number} amount
 * @property {"draft" | "paid"} status
 */

/** @type {Invoice} */
const invoice = { id: 42, amount: 19, status: "settled" };
// Type '"settled"' is not assignable to type '"draft" | "paid"'.
Good to know

The file stays a runnable .js: no build step, no extra tool to install. It is the shortest road to typing an existing code base.


Frequently asked questions

Question

Does JSDoc replace TypeScript?

On a small project, often yes: the same checks, without a compilation step. On a larger base the syntax turns verbose, and advanced features such as conditional types express poorly inside a comment. The move to real TypeScript files then happens on its own.


Question

Should every function be commented?

No. A short function with an explicit name documents itself, and a comment that merely repeats the parameter name adds nothing. Keep JSDoc for exported functions, for those whose contract is not obvious, and for anything carrying optional parameters.


Question

What happens when the comment lies?

Without @ts-check, absolutely nothing: the comment is free text and no one confronts it with the code. With checking turned on it becomes a constraint like any other, and a false annotation raises an error just as a wrong argument would. That is the whole point of switching it on.

Related terms

Discover our javaScript glossary

Every word of JavaScript explained simply: keywords, built-in objects, methods, errors and concepts. Clear definitions and examples that actually run, to learn and to troubleshoot.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.