DEV Community

Cover image for Learn how to document JavaScript/TypeScript code using JSDoc & Typedoc
Mirza Leka
Mirza Leka

Posted on

Learn how to document JavaScript/TypeScript code using JSDoc & Typedoc

In this blog, you'll learn how to document your JS/TS code, how to give more context to your functionalities using JSDoc, and how to generate documentation files using Typedoc.

Setting up the project

Create a new project using npm:

> npm init -y
Enter fullscreen mode Exit fullscreen mode

For this blog I've created a small app (download code) containing 3 files:

  • src/app.js
  • src/models/user.mjs
  • src/models/todo.mjs

Then update the package.json file to use ES Modules:

{
  "name": "js-docs",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "type": "module", // <--- this part
  "scripts": {
    "start": "node ./src/app.js",
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}
Enter fullscreen mode Exit fullscreen mode

Basic Todo class

// todo.mjs
export default class Todo {
  id;
  title;
  description;
  isCompleted;

  constructor(id, title, description, isCompleted) {
    this.id = id;
    this.title = title;
    this.description = description;
    this.isCompleted = isCompleted;
  }
}
Enter fullscreen mode Exit fullscreen mode

Basic User class

A user holds a list of Todos.

// user.mjs
export default class User {
  id;
  username;
  #todos = []; // #todos is a private class member

  constructor(id, username) {
    this.id = id;
    this.username = username;
  }

  addTodo(todo) {
    this.#todos.push(todo);
  }

  getTodos() {
    return this.#todos;
  }
}
Enter fullscreen mode Exit fullscreen mode

Now let's put them together.
Back in app.js create an instance of user, followed by an instance of todo.

// app.js
import Todo from './models/todo.mjs';
import User from './models/user.mjs';

const todo = new Todo(1, 'Must write a new blog', 'Something awesome', false);
const user = new User(1, 'Mirzly');
Enter fullscreen mode Exit fullscreen mode

Now assign this todo to a user:

import Todo from './models/todo.mjs';
import User from './models/user.mjs';

const todo = new Todo(1, 'Must write a new blog', 'Something awesome', false);
const user = new User(1, 'Mirzly');

user.addTodo(todo);
const userTodos = user.getTodos();

console.log('userTodos :>> ', userTodos);
Enter fullscreen mode Exit fullscreen mode

If you run the app (using npm start), you should see user todos printed in the console:

-docs>npm start

> js-docs@1.0.0 start
> node ./src/app.js

userTodos :>>  [
  Todo {
    id: 1,
    title: 'Must write a new blog',
    description: 'Something awesome',
    isCompleted: false
  }
]
Enter fullscreen mode Exit fullscreen mode

Adding Docs

If you hover over the Todo or User class, there is very little information about either class.

User-hover

And since JavaScript doesn't have type safety, there is no IntelliSense to tell you what methods are available on the object and what parameters you can pass to them.

no-IntelliSense

This is where JSDoc comes to save the day.

In JavaScript, you can generate docs by simply typing /** and hitting enter. The Visual Studio Code then sets up a wrapper:

/**
 * 
 */
Enter fullscreen mode Exit fullscreen mode

Inside you can describe your classes, interfaces, functions, their properties, and return types however you like:

/**
 * Creates a new User
 * @property {number} id - User Id
 * @property {string} username - User username
 * @method addTodo {Function} - Adds new todo
 * @method getTodos {Function} - Retrieves all todos
 */
export default class User { 
  // ...

  /**
   * Used to add a new todo
   * @param {Todo} todo - New todo
   * @returns {void} - Does not return anything
   */
  addTodo(todo): void {
    this.#todos.push(todo);
  }

  /**
   * Used to retrieve all todos
   * @returns {Todo[]} - Todos list
   */
  getTodos() {
    return this.#todos;
  }

}

Enter fullscreen mode Exit fullscreen mode

Now if you hover over the User class you should see more info.

user-with-docs

This is also applied to the methods that you document:

method-docs

How cool is that?

TypeDoc

Now let's add TypeDoc - Documentation generator for TypeScript.
That said, you need to initialize a TypeScript project:

Setting up TypeScript

> tsc -init
Enter fullscreen mode Exit fullscreen mode

Now paste the following config into the newly generated tsconfig.json file:

{
  "compilerOptions": {
    "target": "es2016",
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "module": "commonjs",
    "outDir": "./dist",
    "esModuleInterop": true,
    "resolveJsonModule": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  }
}
Enter fullscreen mode Exit fullscreen mode

Changing file structure

Now rename all your .js/.mjs files to .ts:

  • src/app.ts
  • src/models/user.ts
  • src/models/todo.ts

Also be sure to remove the "type": "module" from the package.json file as that can confuse Node.js when running the files.

Fixing formatting

TypeScript will complain about the lack of "types" in the files. Here are the changed files:

user.ts

import Todo from './todo';

/**
 * Creates a new User
 * @property {number} id - User Id
 * @property {string} username - User username
 * @method addTodo {Function} - Adds new todo
 * @method getTodos {Function} - Retrieves all todos
 */
export default class User {
  id: number;
  username: string;
  #todos: Todo[] = [];

  constructor(id: number, username: string) {
    this.id = id;
    this.username = username;
  }

  /**
   * Used to add a new todo
   * @param {Todo} todo - New todo
   * @returns {void} - Does not return anything
   */
  addTodo(todo: Todo): void {
    this.#todos.push(todo);
  }

  /**
   * Used to retrieve all todos
   * @returns {Todo[]} - Todos list
   */
  getTodos(): Todo[] {
    return this.#todos;
  }
}

Enter fullscreen mode Exit fullscreen mode

todo.ts

/**
 * Creates a new Todo
 * @property {number} id - Todo id
 * @property {string} title - Todo title
 * @property {string} description - Todo description
 * @property {boolean} isCompleted - Todo isCompleted status
 */
export default class Todo {
  id: number;
  title: string;
  description: string;
  isCompleted: boolean;

  constructor(id: number, title: string, description: string, isCompleted: boolean) {
    this.id = id;
    this.title = title;
    this.description = description;
    this.isCompleted = isCompleted;
  }
}

Enter fullscreen mode Exit fullscreen mode

Running the app (TS)

You need to install ts-node to run the Typescript files:

> npm i -D ts-node
Enter fullscreen mode Exit fullscreen mode

Now add ts-node to the start script in the package.json file:

{
  "name": "js-docs",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "start": "ts-node ./src/app.ts"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "ts-node": "^10.9.2"
  }
}
Enter fullscreen mode Exit fullscreen mode

Running the app using npm start should print the same result as before.

Adding TypeDoc

Firstly, install Typedoc using npm:

> npm i typedoc -D
Enter fullscreen mode Exit fullscreen mode

Then update the tsconfig.json file with Typedoc configuration:

{
  "compilerOptions": {...},
  "typedocOptions": {
    "entryPoints": [
      "src/models/*.ts" // <--- take everything from this location
    ],
    "out": "docs/typedoc" // <--- output directory
  }
}
Enter fullscreen mode Exit fullscreen mode

Lastly, add a script that is used from running Typedoc

  "scripts": {
    "start": "ts-node ./src/app.ts",
    "type-docs": "typedoc" // <-- reads config from tsconfig.json
  },
Enter fullscreen mode Exit fullscreen mode

Run the script using:

> npm run type-docs

[info] Documentation generated at ./docs/typedoc
Enter fullscreen mode Exit fullscreen mode

This will generate HTML docs page in the specified path ("out": "docs/typedoc") that you can open in your web browser.

docs-preview1

docs-preview2

More complex projects will have better-detailed docs.

docs-preview3

That's all from me today.
If you'd like to learn more make sure to check out my other blog as well on Medium and follow me on Twitter to stay up to date with my content updates.

Bye for now 👋

Top comments (3)

Collapse
 
lexlohr profile image
Alex Lohr

One of my favorite tricks is using markdown in JSDoc comments, as it is supported by virtually all IDEs and editors with JSDoc support.

Collapse
 
mirzaleka profile image
Mirza Leka

Really? I haven't tried that. Thanks for the input

Collapse
 
gautamvaishnav profile image
Gautam Vaishnav

The typescript one is awesome 😍😍😍