JSDoc 参考资料

下面的列表概述了在使用 JSDoc 注释为 JavaScript 文件提供类型信息时当前支持的构造。

🌐 The list below outlines which constructs are currently supported when using JSDoc annotations to provide type information in JavaScript files.

注意:

🌐 Note:

  • 未在下方明确列出的任何标签(例如 @async)尚不受支持。
  • 在 TypeScript 文件中仅支持文档标签。其余标签仅在 JavaScript 文件中支持。

类型

🌐 Types

🌐 Classes

文档

🌐 Documentation

文档标签适用于 TypeScript 和 JavaScript。

🌐 Documentation tags work in both TypeScript and JavaScript.

其他

🌐 Other

其含义通常与 jsdoc.app 上所给标签的含义相同,或是其超集。下面的代码描述了这些差异,并给出每个标签的一些示例用法。

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

**注意:**你可以使用 playground 来探索 JSDoc 支持

类型

🌐 Types

@type

你可以使用“@type”标签来引用类型。类型可以是:

🌐 You can reference types with the “@type” tag. The type can be:

  1. 原始的,比如 stringnumber
  2. 在 TypeScript 声明中声明,全局或导入。
  3. 在 JSDoc @typedef 标签中声明。

你可以使用大多数 JSDoc 类型语法以及任何 TypeScript 语法,从 最基础的如 string最高级的,如条件类型

🌐 You can use most JSDoc type syntax and any TypeScript syntax, from the most basic like string to the most advanced, like conditional types.

js
/**
* @type {string}
*/
var s;
 
/** @type {Window} */
var win;
 
/** @type {PromiseLike<string>} */
var promisedString;
 
// You can specify an HTML Element with DOM properties
/** @type {HTMLElement} */
var myElement = document.querySelector(selector);
element.dataset.myData = "";
Try

@type 可以指定联合类型——例如,某个东西可以是字符串或布尔值。

js
/**
* @type {string | boolean}
*/
var sb;
Try

你可以使用多种语法指定数组类型:

🌐 You can specify array types using a variety of syntaxes:

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

你也可以指定对象字面量类型。例如,一个具有属性 ‘a’(字符串)和 ‘b’(数字)的对象使用以下语法:

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

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

你可以使用标准 JSDoc 语法或 TypeScript 语法,使用字符串和数字索引签名来指定类映射和类数组对象。

🌐 You can specify map-like and array-like objects using string and number index signatures, using either standard JSDoc syntax or TypeScript syntax.

js
/**
* A map-like object that maps arbitrary `string` properties to `number`s.
*
* @type {Object.<string, number>}
*/
var stringToNumber;
 
/** @type {Object.<number, object>} */
var arrayLike;
Try

前面两种类型相当于 TypeScript 类型 { [x: string]: number }{ [x: number]: any }。编译器可以理解这两种语法。

🌐 The preceding two types are equivalent to the TypeScript types { [x: string]: number } and { [x: number]: any }. The compiler understands both syntaxes.

你可以使用 TypeScript 或 Google Closure 语法指定函数类型:

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

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

或者你也可以直接使用未指定的 Function 类型:

🌐 Or you can just use the unspecified Function type:

js
/** @type {Function} */
var fn7;
/** @type {function} */
var fn6;
Try

Closure 的其他类型也可以工作:

🌐 Other types from Closure also work:

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

演员阵容

🌐 Casts

TypeScript 借用了 Google Closure 的类型转换语法。这允许你通过在任何括号表达式前添加 @type 标签来将类型转换为其他类型。

🌐 TypeScript borrows cast syntax from Google Closure. This lets you cast types to other types by adding a @type tag before any parenthesized expression.

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

你甚至可以像 TypeScript 一样转换为 const

🌐 You can even cast to const just like TypeScript:

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

导入类型

🌐 Import types

你可以使用 import types 从其他文件导入声明。这种语法是 TypeScript 特有的,与 JSDoc 标准不同:

🌐 You can import declarations from other files using import types. This syntax is TypeScript-specific and differs from the JSDoc standard:

js
// @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}...`);
}
Try

import types can be used to get the type of a value from a module if you don’t know the type, or if it has a large type that is annoying to type:

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

@import

@import 标签可以让我们引用其他文件的导出内容。

🌐 The @import tag can let us reference exports from other files.

js
/**
* @import {Pet} from "./types"
*/
 
/**
* @type {Pet}
*/
var myPet;
myPet.name;
Try

这些标签实际上并不在运行时导入文件,它们带入范围的符号只能在 JSDoc 注释中用于类型检查。

🌐 These tags don’t actually import files at runtime, and the symbols they bring into scope can only be used within JSDoc comments for type-checking.

js
// @filename: dog.js
export class Dog {
woof() {
console.log("Woof!");
}
}
 
// @filename: main.js
/** @import { Dog } from "./dog.js" */
 
const d = new Dog(); // error!
Try

@param@returns

🌐 @param and @returns

@param 使用与 @type 相同的类型语法,但增加了一个参数名称。参数也可以通过将名称用方括号括起来来声明为可选项:

js
// Parameters may be declared in a variety of syntactic forms
/**
* @param {string} p1 - A string param.
* @param {string=} p2 - An optional param (Google Closure syntax)
* @param {string} [p3] - Another optional param (JSDoc syntax).
* @param {string} [p4="test"] - An optional param with a default value
* @returns {string} This is the result
*/
function stringsStringStrings(p1, p2, p3, p4) {
// TODO
}
Try

同样,对于函数的返回类型:

🌐 Likewise, for the return type of a function:

js
/**
* @return {PromiseLike<string>}
*/
function ps() {}
 
/**
* @returns {{ a: string, b: number }} - May use '@returns' as well as '@return'
*/
function ab() {}
Try

@typedef@callback@param

🌐 @typedef, @callback, and @param

你可以使用 @typedef 定义复杂类型。类似的语法也适用于 @param

🌐 You can define complex types with @typedef. Similar syntax works with @param.

js
/**
* @typedef {Object} SpecialType - creates a new type named 'SpecialType'
* @property {string} prop1 - a string property of SpecialType
* @property {number} prop2 - a number property of SpecialType
* @property {number=} prop3 - an optional number property of SpecialType
* @prop {number} [prop4] - an optional number property of SpecialType
* @prop {number} [prop5=42] - an optional number property of SpecialType with default
*/
 
/** @type {SpecialType} */
var specialTypeObject;
specialTypeObject.prop3;
Try

你可以在第一行使用 objectObject

🌐 You can use either object or Object on the first line.

js
/**
* @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;
Try

@param 允许对一次性类型指定使用类似的语法。请注意,嵌套属性名称必须加上参数名称作为前缀:

js
/**
* @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;
}
Try

@callback 类似于 @typedef,但它指定的是函数类型而不是对象类型:

js
/**
* @callback Predicate
* @param {string} data
* @param {number} [index]
* @returns {boolean}
*/
 
/** @type {Predicate} */
const ok = (s) => !(s.length % 2);
Try

当然,任何这些类型都可以使用 TypeScript 语法在一行 @typedef 中声明:

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

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

@template

你可以使用 @template 标签声明类型参数。这让你可以创建通用的函数、类或类型:

🌐 You can declare type parameters with the @template tag. This lets you make functions, classes, or types that are generic:

js
/**
* @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({});
Try

使用逗号或多个标签来声明多个类型参数:

🌐 Use comma or multiple tags to declare multiple type parameters:

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

你也可以在类型参数名称之前指定类型约束。 列表中只有第一个类型参数会被约束:

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

js
/**
* @template {string} K - K must be a string or string literal
* @template {{ serious(): string }} Seriousalizable - must have a serious method
* @param {K} key
* @param {Seriousalizable} object
*/
function seriousalize(key, object) {
// ????
}
Try

最后,你可以为类型参数指定默认值:

🌐 Finally, you can specify a default for a type parameter:

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

@satisfies

@satisfies 提供了在 TypeScript 中访问后缀 操作符 satisfies 的功能。Satisfies 用于声明一个值实现了某种类型,但不会影响该值的类型。

js
// @ts-check
/**
* @typedef {"hello world" | "Hello, world"} WelcomeMessage
*/
 
/** @satisfies {WelcomeMessage} */
const message = "hello world"
const message: "hello world"
 
/** @satisfies {WelcomeMessage} */
Type '"Hello world!"' does not satisfy the expected type 'WelcomeMessage'.1360Type '"Hello world!"' does not satisfy the expected type 'WelcomeMessage'.
const failingMessage = "Hello world!"
 
/** @type {WelcomeMessage} */
const messageUsingType = "hello world"
const messageUsingType: WelcomeMessage
Try

🌐 Classes

类可以声明为 ES6 类。

🌐 Classes can be declared as ES6 classes.

js
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);
Try

它们也可以被声明为构造函数;为此可以同时使用 @constructor@this

🌐 They can also be declared as constructor functions; use @constructor along with @this for this.

属性修饰符

🌐 Property Modifiers

@public@private@protected 在 TypeScript 中的作用与 publicprivateprotected 完全相同:

js
// @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'.2341Property 'identifier' is private and only accessible within class 'Car'.
Try
  • @public 总是默认存在,可以省略,但它表示某个属性可以从任意位置访问。
  • @private 意味着一个属性只能在其所在的类中使用。
  • @protected 意味着一个属性只能在包含它的类及其所有派生子类中使用,而不能在包含类的不同实例上使用。

@public@private@protected 在构造函数中不起作用。

@readonly

@readonly 修饰符确保一个属性仅在初始化期间被写入。

🌐 The @readonly modifier ensures that a property is only ever written to during initialization.

js
// @ts-check
 
class Car {
constructor() {
/** @readonly */
this.identifier = 100;
}
 
printIdentifier() {
console.log(this.identifier);
}
}
 
const c = new Car();
console.log(c.identifier);
Try

@override

@override 的用法与 TypeScript 中相同;在重写基类方法的方法上使用它:

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

在 tsconfig 中设置 noImplicitOverride: true 以检查覆盖项。

🌐 Set noImplicitOverride: true in tsconfig to check overrides.

@extends

当 JavaScript 类继承一个泛型基类时,没有 JavaScript 语法可以传递类型参数。@extends 标签允许这样做:

🌐 When JavaScript classes extend a generic base class, there is no JavaScript syntax for passing a type argument. The @extends tag allows this:

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

请注意,@extends 仅适用于类。目前,构造函数无法扩展类。

🌐 Note that @extends only works with classes. Currently, there is no way for a constructor function to extend a class.

@implements

同样地,没有 JavaScript 语法来实现 TypeScript 接口。@implements 标签的作用和在 TypeScript 中一样:

🌐 In the same way, there is no JavaScript syntax for implementing a TypeScript interface. The @implements tag works just like in TypeScript:

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

@constructor

编译器会根据 this 属性的赋值推断构造函数,但如果你添加一个 @constructor 标签,可以让检查更严格、建议更准确:

🌐 The compiler infers constructor functions based on this-property assignments, but you can make checking stricter and suggestions better if you add a @constructor tag:

js
/**
* @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 assignable to parameter of type 'string'.2345Argument of type 'number' is not assignable 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'?2348Value of type 'typeof C' is not callable. Did you mean to include 'new'?
Try

注意:错误信息仅会出现在启用了 a JSConfigcheckJs 的 JS 代码库中。

@constructor 中,this 会在构造函数 C 内被检查,因此你会收到 initialize 方法的建议,并且如果传入数字会报错。如果你调用 C 而不是进行构造,编辑器也可能会显示警告。

🌐 With @constructor, this is checked inside the constructor function C, so you will get suggestions for the initialize method and an error if you pass it a number. Your editor may also show warnings if you call C instead of constructing it.

不幸的是,这意味着既可调用又是构造函数的函数不能使用 @constructor

🌐 Unfortunately, this means that constructor functions that are also callable cannot use @constructor.

@this

编译器通常可以在有一些上下文信息可用时推断出 this 的类型。当没有上下文时,你可以使用 @this 显式指定 this 的类型:

🌐 The compiler can usually figure out the type of this when it has some context to work with. When it doesn’t, you can explicitly specify the type of this with @this:

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

文档

🌐 Documentation

@deprecated

当一个函数、方法或属性被弃用时,你可以通过在其上添加 /** @deprecated */ JSDoc 注释来让用户知道。该信息会在补全列表中显示,并作为一个建议性诊断提示供编辑器特别处理。在像 VS Code 这样的编辑器中,弃用的值通常会以删除线的样式显示 像这样

🌐 When a function, method, or property is deprecated you can let users know by marking it with a /** @deprecated */ JSDoc comment. That information is surfaced in completion lists and as a suggestion diagnostic that editors can handle specially. In an editor like VS Code, deprecated values are typically displayed in a strike-through style like this.

js
/** @deprecated */
const apiV1 = {};
const apiV2 = {};
 
apiV;
   
 
 
Try

@see

@see 让你可以链接到程序中的其他名称:

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

一些编辑器会将 Box 转换为链接,以便轻松跳转和返回。

🌐 Some editors will turn Box into a link to make it easy to jump there and back.

@link 类似于 @see,只是它可以在其他标签内使用:

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

你还可以链接属性:

🌐 You can also link a property:

ts
type Pet = {
name: string
hello: () => string
}
 
/**
* Note: you should implement the {@link Pet.hello} method of Pet.
*/
function hello(p: Pet) {
p.hello()
}
Try

或者使用可选名称:

🌐 Or with an optional name:

ts
type Pet = {
name: string
hello: () => string
}
 
/**
* Note: you should implement the {@link Pet.hello | hello} method of Pet.
*/
function hello(p: Pet) {
p.hello()
}
Try

其他

🌐 Other

@enum

@enum 标签允许你创建一个对象字面量,其成员都是指定类型。与 JavaScript 中的大多数对象字面量不同,它不允许其他成员。 @enum 是为了兼容 Google Closure 的 @enum 标签而设计的。

🌐 The @enum tag allows you to create an object literal whose members are all of a specified type. Unlike most object literals in JavaScript, it does not allow other members. @enum is intended for compatibility with Google Closure’s @enum tag.

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

请注意,@enum 与 TypeScript 的 enum 很不同,而且要简单得多。不过,与 TypeScript 的枚举不同,@enum 可以是任何类型:

🌐 Note that @enum is quite different from, and much simpler than, TypeScript’s enum. However, unlike TypeScript’s enums, @enum can have any type:

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

@author

你可以使用 @author 指定项目的作者:

🌐 You can specify the author of an item with @author:

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

记得用尖括号把电子邮件地址括起来。否则,@example 会被解析为一个新标签。

🌐 Remember to surround the email address with angle brackets. Otherwise, @example will be parsed as a new tag.

其他支持的模式

🌐 Other supported patterns

js
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();
}
Try

不支持的模式

🌐 Unsupported patterns

对象字面类型中属性类型的后缀等于未指定可选属性:

🌐 Postfix equals on a property type in an object literal type doesn’t specify an optional property:

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

只有在启用 strictNullChecks 时,可空类型才有意义:

🌐 Nullable types only have meaning if strictNullChecks is on:

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

TypeScript 原生语法是联合类型:

🌐 The TypeScript-native syntax is a union type:

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

不可为 null 的类型没有意义,并被视为它们的基础类型:

🌐 Non-nullable types have no meaning and are treated just as their original type:

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

与 JSDoc 的类型系统不同,TypeScript 只允许你标记类型是否包含 null。没有显式的非空性——如果 strictNullChecks 开启,那么 number 是不可为空的。如果关闭,那么 number 是可为空的。

🌐 Unlike JSDoc’s type system, TypeScript only allows you to mark types as containing null or not. There is no explicit non-nullability — if strictNullChecks is on, then number is not nullable. If it is off, then number is nullable.

不支持的标签

🌐 Unsupported tags

TypeScript 会忽略任何不受支持的 JSDoc 标签。

🌐 TypeScript ignores any unsupported JSDoc tags.

以下标签有未解决的问题来支持它们:

🌐 The following tags have open issues to support them:

旧版类型同义词

🌐 Legacy type synonyms

为了与旧的 JavaScript 代码兼容,一些常见类型被赋予了别名。 有些别名与现有类型相同,但大多数很少使用。 例如,String 被视为 string 的别名。 尽管 String 是 TypeScript 中的一个类型,旧的 JSDoc 经常使用它来表示 string。 此外,在 TypeScript 中,基本类型的大写版本是封装类型——几乎总是使用错误。 因此,编译器根据在旧 JSDoc 中的使用情况将这些类型视为同义词:

🌐 A number of common types are given aliases for compatibility with old JavaScript code. Some of the aliases are the same as existing types, although most of those are rarely used. For example, String is treated as an alias for string. Even though String is a type in TypeScript, old JSDoc often uses it to mean string. Besides, in TypeScript, the capitalized versions of primitive types are wrapper types — almost always a mistake to use. So the compiler treats these types as synonyms based on usage in old JSDoc:

  • String -> string
  • Number -> number
  • Boolean -> boolean
  • Void -> void
  • Undefined -> undefined
  • Null -> null
  • function -> Function
  • array -> Array<any>
  • promise -> Promise<any>
  • Object -> any
  • object -> any

noImplicitAny: true 时,最后四个别名被关闭:

🌐 The last four aliases are turned off when noImplicitAny: true:

  • objectObject 是内建类型,尽管 Object 很少使用。
  • arraypromise 不是内置的,但可能在你的程序的某处被声明过。