Better documentation in TS & JS

How to write better docs in Javascript with rich metadata

Adding metadata to your documentation

Providing good documentation is an essential task for every developer. Not only does it help your peers to quickly understand your reasoning and maybe thought process, but it also helps you to get into the code faster in case you return to it after a couple of months.

I therefore thought to create an (incomplete) list of special tags to use with JSDoc-comments. Those are the ones I personally use most often and that have proven to provide a real benefit.

A basic starter

The following code example shows a simple, basic example that should be used for every documentation. It annotates the purpose, parameters as well as the return type.

/**
 * Get a sum all terms provided.
 * 
 * @param {...number} terms      Array of terms to sum up.
 * @returns {number}             Sum of terms.
 */
export function sum(...terms: number[]){
  return terms.reduce((acc,cv) => acc + cv, 0);
}

Example code in the documentation

You can provide a real inline code example with the “@example”-tag to make certain use cases clearer. This tag can also be used to quickly show possible edge cases in a real-world scenario.

/**
 * Get a sum all terms provided.
 * 
 * @example
 * ```ts
 * import { sum } from "./source";
 * const result = sum(40, 2);
 * ```
 */
export function sum(...terms: number[]){
  return terms.reduce((acc,cv) => acc + cv, 0);
}

Member of which module

Use the “@memberOf”-tag to define which module or parent variable hosts the documented code.

/**
 * @memberOf module:source
 */
export function sum(...terms: number[]){
  return terms.reduce((acc,cv) => acc + cv, 0);
}

Link annotation

You can use the “@see”-tag together with the “@link”-tag to provide a correctly formatted URL-documentation, instead of pasting some URLs inline of the main documentation.

/**
 * @see (@link module:source.sum}
 * @see (@link https://www.some-source.com}
 */
export function sum(...terms: number[]){
  return terms.reduce((acc,cv) => acc + cv, 0);
}

Generic type documentation

If your code uses generic types, you can use the “@template”-tag to define the generic type name. This name is then used in the common “@param”-tags as type reference.

/**
 * @template T
 * @param {...T}       Array of numbers to sum up.
 * @returns {number}   Sum of terms.
 */
export function sum(...terms: number[]){
  return terms.reduce((acc,cv) => acc + cv, 0);
}

Defining the author of a piece of code

In certain cases, it’s important to annotate the author as well. This can be simply accomplished with the “@author”-tag. You can not only provide your name, but also an email as contact reference.

/**
 * @author Tom Schönmann <tom@flaming.codes>
 */
export function sum(...terms: number[]){
  return terms.reduce((acc,cv) => acc + cv, 0);
}

Deprecated code

There’s not much to tell about the “@deprecated”-tag, as it does exactly what you’d expect. This tag is commonly used in APIs and can also reference the new code.

/**
 * @deprecated    Use 'add(...)' instead.
 * @see {@link module:source/add}
 */
export function sum(...terms: number[]){
  return terms.reduce((acc,cv) => acc + cv, 0);
}

Version

Use the “@version”-tag to document a version for the given code. Note that this tag does not reference the application version, but really its own one. An increment of this version means this specific code has changed.

/**
 * @version    1.0.0
 */
export function sum(...terms: number[]){
  return terms.reduce((acc,cv) => acc + cv, 0);
}

Since when the code is available to use

You can use the “@since”-tag to document from which version number the following code has been added to the public API. Important to note here is that the version now references the application-scope. This contrasts with the “@version”-tag from before, which is scoped to the specific code block it documents.

/**
 * @since    2.0.1
 */
export function sum(...terms: number[]){
  return terms.reduce((acc,cv) => acc + cv, 0);
}

Suggestions

Related

Addendum

Languages