How to Use JSDoc for JavaScript Type Checking

JSDoc bridges the gap between pure JavaScript and static type systems by using structured comment blocks to define types, describe APIs, and validate code. By pairing standard JSDoc annotations with modern editor tooling and the TypeScript compiler, developers can achieve robust documentation, intelligent autocompletion, and compile-time type safety directly in plain JavaScript files without requiring a dedicated build step or transpilation.

Understanding JSDoc Comments

JSDoc uses block comments starting with an extra asterisk (/** ... */) placed immediately above the code construct they describe. Inside these blocks, specific tags starting with the @ symbol are used to describe the intent, structure, and constraints of functions, variables, and objects.

Common tags include: * @param {type} name - description: Documents a function parameter and its expected type. * @returns {type} description: Defines the return type and behavior of a function. * @type {type}: Explicitly types a variable or property. * @typedef: Declares custom object shapes or union types for reuse. * @deprecated: Marks code that should no longer be used.

/**
 * Calculates the total cost including tax.
 * @param {number} price - The base price of the item.
 * @param {number} taxRate - The applicable tax rate (e.g., 0.08 for 8%).
 * @returns {number} The total cost.
 */
function calculateTotal(price, taxRate) {
  return price + (price * taxRate);
}

Enabling Real-Time Type Checking

Modern editors such as Visual Studio Code natively run the TypeScript Language Server in the background. This server parses JSDoc comments to provide inline type checking, parameter hints, and code refactoring suggestions.

To activate static type checking inside plain JavaScript files, you can use two approaches:

  1. Per-File Activation: Add // @ts-check on the very first line of a JavaScript file. The editor will immediately highlight type mismatches, missing properties, or invalid function calls with red squiggles.
  2. Project-Wide Activation: Create a jsconfig.json or tsconfig.json file in the root of the project with "checkJs": true. This enforces type checking across all JavaScript files in the project.
{
  "compilerOptions": {
    "checkJs": true,
    "allowJs": true,
    "noEmit": true
  },
  "include": ["src/**/*"]
}

Defining Complex Types and Interfaces

JSDoc can model complex data structures using @typedef and @property. This allows you to create reusable models similar to TypeScript interfaces.

/**
 * @typedef {Object} User
 * @property {number} id - Unique user identifier.
 * @property {string} name - User's full name.
 * @property {string} [email] - Optional email address.
 * @property {'admin' | 'member' | 'guest'} role - Union type for user roles.
 */

/**
 * Updates an existing user record.
 * @param {User} user - The user object to update.
 */
function updateUser(user) {
  console.log(`Updating ${user.name} with role ${user.role}`);
}

You can also import types directly from TypeScript definition files (.d.ts) or other JavaScript modules using the import() syntax inside JSDoc tags:

/** @type {import('express').Request} */
let req;

Automating Documentation and Validation

Beyond editor feedback, JSDoc enables two powerful workflow enhancements:

By using JSDoc, teams get the majority of TypeScript’s type safety and IDE support while maintaining pure, uncompiled JavaScript that runs natively in any browser or Node.js environment.