JSDoc 参考

下面的列表概述了在 JavaScript 文件中使用 JSDoc 注解提供类型信息时,目前支持哪些构造。

注意:

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

类型

类

文档

文档标签在 TypeScript 和 JavaScript 中均可使用。

其他

它们的含义通常与 jsdoc.app 上给出的标签含义相同或是其超集。下面的代码说明了各标签的差异,并给出了一些用法示例。

注意:你可以使用Playground 来探索 JSDoc 支持。

类型

@type

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

  1. 原始类型,如 string 或 number。
  2. 在 TypeScript 声明中声明的类型,可以是全局的或导入的。
  3. 在 JSDoc @typedef 标签中声明的类型。

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

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 可以指定联合类型——例如,某个值既可以是 string 也可以是 boolean。

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

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

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

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

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

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

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 }。编译器能理解这两种语法。

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

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

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

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

Closure 中的其他类型同样可用:

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

类型转换

TypeScript 借用了 Google Closure 的类型转换语法。你可以在任何带括号的表达式前添加 @type 标签,从而将类型转换为其他类型。

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

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

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

导入类型

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

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

当你不知道某个值的类型,或者它的类型很大、写起来很麻烦时,可以使用导入类型从模块中获取该值的类型:

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

@import

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

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

这些标签在运行时并不会真正导入文件,它们引入作用域的符号只能在 JSDoc 注释中用于类型检查。

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 使用与 @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

同样,函数的返回类型也可以这样写:

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 定义复杂类型。@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

第一行可以使用 object 或 Object。

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

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

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

@template

你可以用 @template 标签声明类型参数。这样就能让函数、类或类型具有泛型:

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

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

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

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

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

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

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

类

类可以声明为 ES6 类。

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。

属性修饰符

@public、@private 和 @protected 的作用与 TypeScript 中的 public、private 和 protected 完全一样:

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 修饰符确保属性只在初始化时被写入。

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 以检查重写。

@extends

当 JavaScript 类继承泛型基类时,没有传递类型实参的 JavaScript 语法。@extends 标签可以实现这一点:

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

注意,@extends 只对类有效。目前,构造函数无法继承类。

@implements

同样,JavaScript 也没有实现 TypeScript 接口的语法。@implements 标签的用法与 TypeScript 中完全一致:

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

@constructor

编译器会根据 this 属性赋值推断构造函数,不过如果你添加 @constructor 标签,就能让检查更严格、建议更完善:

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

注意:错误信息只会出现在启用了 JSConfig 和 checkJs 的 JS 代码库中。

使用 @constructor 后,构造函数 C 内部的 this 会接受检查,因此你会得到 initialize 方法的建议,而传入数字则会报错。如果你调用 C 而不是构造它,编辑器还可能显示警告。

遗憾的是,这意味着既可调用又能作为构造函数的函数无法使用 @constructor。

@this

当有一些上下文可供参考时,编译器通常能推断出 this 的类型。如果推断不出来,你可以用 @this 显式指定 this 的类型:

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

文档

@deprecated

当函数、方法或属性被弃用时,你可以用 /** @deprecated */ JSDoc 注释标记它,让用户知晓。该信息会显示在补全列表中,并作为一条建议诊断信息呈现,编辑器可以对其做特殊处理。在 VS Code 这类编辑器中,已弃用的值通常以删除线样式显示,像这样。

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 变成链接,方便来回跳转。

@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

你也可以链接某个属性:

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

或者带一个可选名称:

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

其他

@enum

@enum 标签允许你创建一个对象字面量,其成员全部属于指定的类型。与 JavaScript 中的大多数对象字面量不同,它不允许存在其他成员。@enum 旨在与 Google Closure 的 @enum 标签保持兼容。

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

注意,@enum 与 TypeScript 的 enum 差别很大,也简单得多。不过,与 TypeScript 的枚举不同,@enum 的成员可以是任意类型:

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

@author

你可以用 @author 指定某个条目的作者:

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

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

其他支持的写法

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

不支持的写法

对象字面量类型中,属性类型后面的等号后缀并不表示可选属性:

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 时才有意义:

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

TypeScript 原生的写法是联合类型:

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

不可空类型没有实际含义,会被当作其原始类型处理:

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

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

不支持的标签

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

以下标签有请求支持的未解决 issue:

旧式类型同义词

为了兼容旧的 JavaScript 代码,许多常见类型都被赋予了别名。其中一些别名与现有类型相同,不过它们大多很少使用。例如,String 会被当作 string 的别名。尽管 String 在 TypeScript 中是一个类型,但旧的 JSDoc 常用它来表示 string。此外,在 TypeScript 中,原始类型的大写形式是包装类型——几乎总是误用。因此,编译器根据旧 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 时,最后四个别名会被关闭:

  • object 和 Object 是内置类型,不过 Object 很少被使用。
  • array 和 promise 不是内置的,但可能在你程序的某处声明过。

TypeScript 文档是一个开源项目。欢迎发送 Pull Request 帮助我们改进这些页面 ❤

最后更新:2026 年 10 月 23 日