Skip to content

jsdoc reference

About 2685 wordsAbout 9 min

javascript

2022-11-22

This article is translated from Official Document JSDoc Reference


The following list outlines what structures are currently supported when using JSDoc annotations to provide type information in a JavaScript file.

Note that any tags not explicitly listed below (e.g. @async ) are not supported.

Types:

Classes:

Documentation:

Document tags are valid in both TypeScript and JavaScript.

Other:

Its meaning is usually the same as the tag given in jsdoc.app, or a superset. The code below describes the differences and gives some example usage of each tag.

Types

@type

You can declare a type using the @type tag, the type can be:

  • Original, such as string, number, etc.
  • Declared in the typescript declaration file, can be global or imported.
  • declared in the @typedef tag.

You can use most JSDoc type syntax and any TypeScript syntax, From the most basic syntax string to the most advanced syntax (such as conditional types).

/**
 * @type {string}
 */
var s

/** @type {Window} */
var win

/** @type {PromiseLike<string>} */
var promisedString

// You can specify an HTML element with the DOM attribute
/** @type {HTMLElement} */
var myElement = document.querySelector(selector)
element.dataset.myData = ''

@type can specify a union type - for example, something can be a string or a boolean value.

/**
 * @type {string | boolean}
 */
var sOrB

There are several syntaxes that can be used to specify array types:

/** @type {number[]} */
var ns
/** @type {Array.<number>} */
var jsdoc
/** @type {Array<number>} */
var nas

You can also specify object literal types. For example, an object with attributes "a" (string) and "b" (number) uses the following syntax:

/** @type {{ a: string, b: number }} */
var var9

You can use string and numeric index signatures to specify class Map and class Array objects using standard JSDoc syntax or TypeScript syntax.

/**
 * A map-like object that maps any `string` attribute to `number`.
 *
 * @type {Object.<string, number>}
 */
var stringToNumber

/** @type {Object.<number, object>} */
var arrayLike

The first two types are equivalent to TypeScript types { [x: string]: number } and { [x: number]: any }. The compiler understands these two syntaxes.

You can specify function types using TypeScript or Google Closure syntax:

/** @type {function(string, boolean): number} Closure syntax */
var sbn
/** @type {(s: string, b: boolean) => number} TypeScript syntax */
var sbn2

Or you can just use the unspecified Function type:

/** @type {Function} */
var fn7
/** @type {function} */
var fn6

Other types in Closure are also applicable:

/**
 * @type {*} - can be 'any' type
 */
var star
/**
 * @type {?} - unknown type (same as 'any')
 */
var question

Casts

TypeScript borrows Google Closure's cast syntax. This allows @type to convert a type to another type by adding a tag before any bracketed expression.

/**
 * @type {number | string}
 */
var numberOrString = Math.random() < 0.5 ? 'hello' : 100
var typeAssertedNumber = /** @type {number} */ (numberOrString)

const can even be converted like TypeScript:

let one = /** @type {const} */ (1)

Import types

You can use Type Import to import type declarations from other files. This syntax is TypeScript-specific and is different from the JSDoc standard:

// @filename: types.d.ts
export type Pet = {
 name: string,
};

// @filename: main.js
/**
 * @param {import("./types").Pet} p
 */
function walk(p) {
 console.log(`Walking ${p.name}...`);
}

Import types can be used in type alias declarations:

/**
 * @typedef {import("./types").Pet} Pet
 */

/**
 * @type {Pet}
 */
var myPet
myPet.name

If you do not know the type of value in the module, or if the type in the module is large and difficult to obtain, you can use the import type to get the type of value from the module:

/**
 * @type {typeof import("./accounts").userAccount}
 */
var x = require('./accounts').userAccount

@param and @returns

The syntax of @param is the same as the type syntax of @type, but the parameter name is added. This parameter can also be declared optional by enclosing the name in square brackets:

// Parameters can be declared in various syntax forms
/**
 * @param {string} p1 - string parameter
 * @param {string=} p2 - Optional parameters (Google Closure syntax)
 * @param {string} [p3] - Optional parameter (JSDoc syntax).
 * @param {string} [p4="test"] - optional parameters with default values
 * @returns {string} Returns the result
 */
function stringsStringStringStrings(p1, p2, p3, p4) {
  // TODO
}

Similarly, for the return type of the function:

/**
 * @return {PromiseLike<string>}
 */
function ps() {}

/**
 * @returns {{ a: string, b: number }} - You can use '@returns' or '@return'
 */
function ab() {}

@typedef, @callback, and @param

More complex types can be defined using @typedef. A similar syntax also applies to @param.

/**
 * @typedef {Object} SpecialType - Create a type named 'SpecialType'
 * @property {string} prop1 - string type property on SpecialType
 * @property {number} prop2 - Number type property on SpecialType
 * @property {number=} prop3 - an optional number type property on SpecialType
 * @prop {number} [prop4] - An optional number type property on SpecialType
 * @prop {number} [prop5=42] - An optional number type attribute on SpecialType, with the default value of 42
 */

/** @type {SpecialType} */
var specialTypeObject
specialTypeObject.prop3

You can use Object or object on the first line.

/**
 * @typedef {object} SpecialType1 - creates a new type named 'SpecialType1'
 * @property {string} prop1 - a string property of SpecialType1
 * @property {number} prop2 - a number property of SpecialType1
 * @property {number=} prop3 - an optional number property of SpecialType1
 */

/** @type {SpecialType1} */
var specialTypeObject1

@param allows for the use of similar syntax for one-time type specifications. Note that nested property names must be prefixed with parameter names:

/**
 * @param {Object} options - The shape is the same as SpecialType above
 * @param {string} options.prop1
 * @param {number} options.prop2
 * @param {number=} options.prop3
 * @param {number} [options.prop4]
 * @param {number} [options.prop5=42]
 */
function special(options) {
  return (options.prop4 || 1001) + options.prop5
}

@callback is similar to @typedef, but it specifies a function type instead of an object type:

/**
 * @callback Predicate
 * @param {string} data
 * @param {number} [index]
 * @returns {boolean}
 */

/** @type {Predicate} */
const ok = (s) => !(s.length % 2)

Of course, any of these types can be declared in a single line using the TypeScript syntax @typedef:

/** @typedef {{ prop1: string, prop2: string, prop3?: number }} SpecialType */
/** @typedef {(data: string, index?: number) => boolean} Predicate */

@template

Type parameters can be declared using the @template tag. Can be used to create common functions, classes, or types:

/**
 * @template T
 * @param {T} x - A generic parameter that flows through to the return type
 * @returns {T}
 */
function id(x) {
 Return x
}

const a = id('string')
const b = id(123)
const c = id({})

Use commas or multiple tags to declare multiple type parameters:

/**
 * @template T,U,V
 * @template W,X
 */

You can also specify type constraints before the type parameter name. Only the first type parameter in the list is constrained:

/**
 * @template {string} K - K must be a string or string literal
 * @template {{ serious(): string }} Seriously enough - must have a serious method
 * @param {K} key
 * @param {Seriouslyizable} object
 */
function seriousize(key, object) {
  // ?????
}

Finally, you can specify the default value of the type parameter:

/** @template [T=object] */
class Cache {
  /** @param {T} initial */
  constructor(initial) {}
}
let c = new Cache()

@satisfies

@satisfies provides access to satisfies for suffix operators in TypeScript. Satisfies is used to declare that a value implements a certain type, but does not affect the type of the value.

// @ts-check
/**
 * @typedef {"hello world" | "Hello, world"} WelcomeMessage
 */

/** @satisfies {WelcomeMessage} */
const message = 'hello world' // const message: "hello world"

/** @satisfies {WelcomeMessage} */
const failingMessage = 'Hello world!'
// Type '"Hello world!"' does not satisfy the expected type 'WelcomeMessage'.

/** @type {WelcomeMessage} */
const messageUsingType = 'hello world' // const messageUsingType: WelcomeMessage

Classes

Classes can declare ES6 Classes

class C {
  /**
   * @param {number} data
   */
  constructor(data) {
    // property types can be inferred
    this.name = 'foo'

    // or set explicitly
    /** @type {string | null} */
    this.title = null

    // or simply annotated, if they're set elsewhere
    /** @type {number} */
    this.size

    this.initialize(data) // Should error, initializer expects a string
  }
  /**
   * @param {string} s
   */
  initialize = function (s) {
    this.size = s.length
  }
}

var c = new C(0)

// C should only be called with new, but
// because it is JavaScript, this is allowed and
// considered an 'any'.
var result = C(1)

They can also be declared as constructors; they need to be used with @constructor and @this.

Property Modifiers

@public, @private and @protected work exactly the same as public, private, and protected in TypeScript:

// @ts-check

class Car {
  constructor() {
    /** @private */
    this.identifier = 100
  }

  printIdentifier() {
    console.log(this.identifier)
  }
}

const c = new Car()
console.log(c.identifier)
// Property 'identifier' is private and only accessible within class 'Car'.
  • @public is always implicit and can be omitted, but means that the properties can be accessed from anywhere.
  • @private means that the attribute can only be used in the include class.
  • @protected means that properties can only be used in the include class and all derived subclasses, but not on different instances of the include class.

@public, @private, and @protected do not apply to constructors.

@readonly

The @readonly modifier ensures that the attribute is written only during initialization.

// @ts-check

class Car {
  constructor() {
    /** @readonly */
    this.identifier = 100
  }

  printIdentifier() {
    console.log(this.identifier)
  }
}

const c = new Car()
console.log(c.identifier)

@override

@override works the same way as TypeScript; use it on methods that rewrite base class methods:

export class C {
  m() {}
}
class D extends C {
  /** @override */
  m() {}
}

Set noImplicitOverride: true in tsconfig to check for overrides.

@extends

When the JavaScript class extends a general base class, there is no JavaScript syntax for passing type parameters. The @extends tag allows this:

/**
 * @template T
 * @extends {Set<T>}
 */
class SortableSet extends Set {
  // ...
}

Note that @extends is only available for classes. Currently, constructors cannot extend classes.

@implements

Similarly, there is no JavaScript syntax for implementing the TypeScript interface. The @implements tag works just like in TypeScript:

/** @implements {Print} */
class TextBook {
  print() {
    // TODO
  }
}

@constructor

The compiler infers the constructor based on this-property assignment, but if the @constructor tag is added, Can make inspections stricter and provide better advice:

/**
 * @constructor
 * @param {number} data
 */
function C(data) {
  // property types can be inferred
  this.name = 'foo'

  // or set explicitly
  /** @type {string | null} */
  this.title = null

  // or simply annotated, if they're set elsewhere
  /** @type {number} */
  this.size

  this.initialize(data)
  // Argument of type 'number' is not assigned to parameter of type 'string'.
  /**
   * @param {string} s
   */
  C.prototype.initialize = function (s) {
    this.size = s.length
  }

  var c = new C(0)
  c.size

  var result = C(1)
  // Value of type 'typeof C' is not callable. Did you mean to include 'new'?
}

Note: Error messages are displayed only on having JSConfig and checkJs enables the JS code base.

For @constructor, this is checked in the constructor C, so you will get suggestions for initialization methods, and if you pass a number to it, you will get an error. The editor may also display a warning if you call C instead of constructing it.

Unfortunately, this means that the same callable constructor cannot use @constructor.

@this

this When the compiler has some context to use, it can usually find out the type. If not, you can explicitly specify this via the @this tag:

/**
 * @this {HTMLElement}
 * @param {*} e
 */
function callbackForLater(e) {
  this.clientHeight = parseInt(e) // should be fine!
}

Documentation

@deprecated

When a function, method, or property is deprecated, you can let the user know by tagging it with the /** @deprecated */ JSDoc annotation. This information is displayed in the completion list and serves as a recommended diagnosis that the editor can specifically handle. In editors such as VS Code, deprecated values ​​are usually displayed in strikethrough style ~~ like this ~~.

/** @deprecated */
const apiV1 = {}
const apiV2 = {}

@see

@see allows linking to other names in the program:

type Box<T> = { t: T }
/** @see Box for implementation details */
type Boxify<T> = { [K in keyof T]: Box<T> }

Some editors become Box links for easy jumps.

@link is similar to @see, except that it can be used within other tags:

type Box<T> = { t: T }
/** @returns A {@link Box} containing the parameter. */
function box<U>(u: U): Box<U> {
  return { t: u }
}

Other

@enum

The @enum tag allows you to create an object literal whose members are specified. Unlike most object literals in JavaScript, it does not allow other members. @enum is designed to be compatible with Google Closure's @enum tag.

/** @enum {number} */
const JSDocState = {
  BeginningOfLine: 0,
  SawAsterisk: 1,
  SavingComments: 2,
}

JSDocState.SawAsterisk

Note that @enum is completely different from TypeScript's enum and is much simpler than it. However, unlike TypeScript's enum, @enum can be of any type:

/** @enum {function(number): number} */
const MathFuncs = {
  add1: (n) => n + 1,
  id: (n) => -n,
  sub1: (n) => n - 1,
}

MathFuncs.add1

@author

You can specify the author of the project using the following methods:

/**
 * Welcome to awesome.ts
 * @author Ian Awesome <i.am.awesome@example.com>
 */

Remember to enclose your email address in angle brackets. Otherwise, @example will be parsed into a new tag.

Other supported patterns

var someObj = {
  /**
   * @param {string} param1 - JSDocs on property assignments work
   */
  x: function (param1) {},
}

/**
 * As do jsdocs on variable assignments
 * @return {Window}
 */
let someFunc = function () {}

/**
 * And class methods
 * @param {string} greeting The greeting to use
 */
Foo.prototype.sayHi = (greeting) => console.log('Hi!')

/**
 * And arrow function expressions
 * @param {number} x - A multiplier
 */
let myArrow = (x) => x * x

/**
 * Which means it works for function components in JSX too
 * @param {{a: string, b: number}} props - Some param
 */
var fc = (props) => <div>{props.a.charAt(0)}</div>

/**
 * A parameter can be a class constructor, using Google Closure syntax.
 *
 * @param {{new(...args: any[]): object}} C - The class to register
 */
function registerClass(C) {}

/**
 * @param {...string} p1 - A 'rest' arg (array) of strings. (treated as 'any')
 */
function fn10(p1) {}

/**
 * @param {...string} p1 - A 'rest' arg (array) of strings. (treated as 'any')
 */
function fn9(p1) {
  return p1.join()
}

Unsupported patterns

The suffix of the attribute type in the object literal type equals does not specify optional attributes:

/**
 * @type {{ a: string, b: number= }}
 */
var wrong
/**
 * Use postfix question on the property name instead:
 * @type {{ a: string, b?: number }}
 */
var right

strictNullChecks The nullable type only makes sense when opened:

/**
 * @type {?number}
 * With strictNullChecks: true -- number | null
 * With strictNullChecks: false -- number
 */
var nullable

TypeScript native syntax is a union type:

/**
 * @type {number | null}
 * With strictNullChecks: true -- number | null
 * With strictNullChecks: false -- number
 */
var unionNullable

A type that cannot be null has no meaning and is considered its primitive type:

/**
 * @type {!number}
 * Just has type number
 */
var normal

Unlike the type system of JSDoc, TypeScript only allows types to be marked as having null or not. No explicit non-null--null if strictNullChecks is turned on, number is non-null. If it is closed, the number can be empty.

Unsupported tags

TypeScript ignores any unsupported JSDoc tags.

The following tags have issues to be resolved to support them: