Skip to content

Instantly share code, notes, and snippets.

@customcommander
Last active June 26, 2023 05:20
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save customcommander/5206dcb44670e34f6923b62c1781e1d2 to your computer and use it in GitHub Desktop.
Save customcommander/5206dcb44670e34f6923b62c1781e1d2 to your computer and use it in GitHub Desktop.
JSDoc Cheat Sheet

JSDoc Cheat Sheet

Things I found myself researching over and over without taking the time to write them down. Until now.

Table of Contents

  1. Should I use {String} vs {string} or {Number} vs {number} ...?
  2. Type Expression: Optional vs Nullable vs Non-nullable
  3. When do I need to use the @function tag?

Should I use {String} vs {string} or {Number} vs {number} ...?

Strings, numbers and booleans

These aren't interchangeable type expressions. For example if a symbol is meant to hold a literal string you should use {string} and not {String}: (The same is true for {Number} e.g. new Number(42) vs {number} e.g. 42 and {Boolean} e.g. new Boolean and {boolean} e.g. false.)

/** @param {String} x */
const a = x => x;

/** @param {string} x */
const b = x => x;
fn Annotation fn("foo") fn(new String("foo"))
a {String} x
b {string} x

╳ represents the JSC_TYPE_MISMATCH error in GCC.

Examples have been compiled with the Google Closure Compiler and are available here.

Objects and arrays

Objects and arrays are covered respectively by the {Object} and {Array} type expressions which both handle literal and constructor expressions: ({} vs new Object and [] vs new Array)

/** @param {Object} x */
const a = x => x;

/** @param {Array} x */
const b = x => x;
fn Annotation fn() fn(<literal>) fn(<constructor>) fn(null) fn(undefined)
a {Object} x ╳1 ╳2
b {Array} x ╳1 ╳2

╳1 represents the JSC_WRONG_ARGUMENT_COUNT error in GCC.
╳2 represents the JSC_TYPE_MISMATCH error in GCC.

Examples have been compiled using the Google Closure Compiler and are available here.

Note that arrays, objects (and functions) are nullable by default. So {Object} is the same as {?Object} which explains why a(null) passed the type check.

Note that the following are already nullable, and thus prepending ? is redundant, but is recommended so that the intent is clear and explicit: ?Object, ?Array, ?Function

See Types in the Closure Type System

Functions

There are two type expressions: {function()} and {Function}. The former being preferred over the latter as it allows to document parameters and return values.

/** @param {Function} x */
const a = x => x;

/** @param {function()} x */
const b = x => x;
Code {Function} x {function()} x
fn(() => 42);
fn(function () { return 42 });
fn(new Function('return 42'));
fn(); ╳1 ╳1
fn(null); ╳2
fn(undefined); ╳2 ╳2

╳1 represents the JSC_WRONG_ARGUMENT_COUNT error in GCC.
╳2 represents the JSC_TYPE_MISMATCH error in GCC.

Examples have been compiled using the Google Closure Compiler and are available here.

Note that {Function} is the same as {?Function} meaning that it is nullable by default.

Type Expression: Optional vs Nullable vs Non-nullable

A type expression is used to document the type of many different things such as a parameter, a variable or a property or the return value of a function. JSDoc supports the Google Closure Compiler Type System in type expressions.

/** @param {number} x */
const a = x => x;

/** @param {number=} x */
const b = x => x;

/** @param {number} [x] */
const c = x => x;

/** @param {number} [x=42] */
const d = x => x;

/** @param {!number} x */
const e = x => x;

/** @param {!number=} x */
const f = x => x;

/** @param {!number} [x] */
const g = x => x;

/** @param {!number} [x=42] */
const h = x => x;

/** @param {?number} x */
const i = x => x;

/** @param {?number=} x */
const j = x => x;

/** @param {?number} [x] */
const k = x => x;

/** @param {?number} [x=42] */
const l = x => x;
fn Annotation Expect Default fn() fn("42") fn(null) fn(undefined) fn(42)
a {number} x Number ╳1 ╳2 ╳2 ╳2
b {number=} x Number or undefined undefined ╳2 ╳2
c {number} [x] Number or undefined undefined ╳2 ╳2
d {number} [x=42] Number or undefined 42 ╳2 ╳2
e {!number} x Number ╳1 ╳2 ╳2 ╳2
f {!number=} x Number or undefined undefined ╳2 ╳2
g {!number} [x] Number or undefined undefined ╳2 ╳2
h {!number} [x=42] Number or undefined 42 ╳2 ╳2
i {?number} x Number or null ╳1 ╳2 ╳2
j {?number=} x Number, null or undefined undefined ╳2
k {?number} [x] Number, null or undefined undefined ╳2
l {?number} [x=42] Number, null or undefined 42 ╳2

╳1 represents the JSC_WRONG_ARGUMENT_COUNT error in GCC.
╳2 represents the JSC_TYPE_MISMATCH error in GCC.

Examples have been compiled with the Google Closure Compiler and are available here.

When do I need to use the @function tag?

This would be necessary when a function gets assigned to a variable for example.

This marks an object as being a function, even though it may not appear to be one to the parser. It sets the doclet's @kind to 'function'.

See JSDoc @function tag documentation.

If we dump the doclets of index.js with: jsdoc -X index.js

// index.js

/** @param {?} y */
function a(y) {}

/** @param {?} y */
const b = a;

/**
 * @function
 * @param {?} y
 */
const c = a;

Doclet for a:

{
  // ...
  "name": "a",
  "longname": "a",
  "kind": "function",
  "scope": "global"
}

Doclet for b:

{
  // ...
  "name": "b",
  "longname": "b",
  "kind": "constant",
  "scope": "global"
}

Doclet for c:

{
  // ...
  "name": "b",
  "longname": "b",
  "kind": "function",
  "scope": "global"
}

We can see that b doesn't appear as a function to the JSDoc parser. This isn't the case for c as we explicitly marked it as such with the @function tag.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment