jsdoc reference
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:
- Property Modifiers
@public
,@private
,@protected
, @readonly - @override
- @extends (or
@augments
) - @implements
@class
(or @constructor)- @this
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
@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:
@const
(Question #19672)@inheritdoc
(Question #23215)@memberof
(Question #7237)@yields
(Question #23857)