JSDoc 参考
下面的列表概述了在 JavaScript 文件中使用 JSDoc 注释提供类型信息时当前支持的结构。
注意:
- 任何未在下面明确列出的标签(例如
@async)尚未支持。 - TypeScript 文件中仅支持文档标签。其余标签仅在 JavaScript 文件中支持。
类型
类
- 属性修饰符
@public,@private,@protected,@readonly @override@extends(或@augments)@implements@class(或@constructor)@this
文档
文档标签在 TypeScript 和 JavaScript 中都有效。
其他
这些标签的含义通常与 jsdoc.app 上给出的标签含义相同,或者是其超集。 下面的代码描述了差异,并给出了每个标签的一些示例用法。
注意: 你可以使用演练场来探索 JSDoc 支持。
类型
@type
你可以使用 @type 标签引用类型。类型可以是:
- 原始类型,如
string或number。 - 在 TypeScript 声明中声明的类型,无论是全局的还是导入的。
- 在 JSDoc
@typedef标签中声明的类型。
你可以使用大多数 JSDoc 类型语法和任何 TypeScript 语法,从最基本的如 string 到最先进的,如条件类型。
/**
* @type {string}
*/
var s;
/** @type {Window} */
var win;
/** @type {PromiseLike<string>} */
var promisedString;
// 你可以使用 DOM 属性指定一个 HTML 元素
/** @type {HTMLElement} */
var myElement = document.querySelector(selector);
element.dataset.myData = "";Try@type 可以指定联合类型——例如,某物可以是字符串或布尔值。
你可以使用多种语法指定数组类型:
/** @type {number[]} */
var ns;
/** @type {Array.<number>} */
var jsdoc;
/** @type {Array<number>} */
var nas;Try你也可以指定对象字面量类型。 例如,一个具有属性 'a'(字符串)和 'b'(数字)的对象使用以下语法:
你可以使用标准 JSDoc 语法或 TypeScript 语法,通过字符串和数字索引签名来指定类映射和类数组对象。
/**
* 一个类似映射的对象,将任意的 `string` 属性映射到 `number`。
*
* @type {Object.<string, number>}
*/
var stringToNumber;
/** @type {Object.<number, object>} */
var arrayLike;Try前两种类型分别等价于 TypeScript 类型 { [x: string]: number } 和 { [x: number]: any }。编译器理解这两种语法。
你可以使用 TypeScript 或 Google Closure 语法指定函数类型:
/** @type {function(string, boolean): number} Closure 语法 */
var sbn;
/** @type {(s: string, b: boolean) => number} TypeScript 语法 */
var sbn2;Try或者你可以直接使用未指定的 Function 类型:
Closure 的其他类型也可以工作:
类型断言
TypeScript 借鉴了 Google Closure 的断言语法。 这允许你在任何带括号的表达式之前添加一个 @type 标签来将类型转换为其他类型。
/**
* @type {number | string}
*/
var numberOrString = Math.random() < 0.5 ? "hello" : 100;
var typeAssertedNumber = /** @type {number} */ (numberOrString);Try你甚至可以像 TypeScript 一样断言为 const:
导入类型
你可以使用导入类型从其他文件导入声明。 这种语法是 TypeScript 特有的,与 JSDoc 标准不同:
// @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如果你不知道类型,或者如果类型很大而输入麻烦,可以使用导入类型从模块中获取值的类型:
/**
* @type {typeof import("./accounts").userAccount}
*/
var x = require("./accounts").userAccount;Try@import
@import 标签允许我们引用其他文件中的导出。
这些标签实际上并不在运行时导入文件,它们引入作用域的符号只能在 JSDoc 注释中用于类型检查。
// @filename: dog.js
export class Dog {
woof() {
console.log("Woof!");
}
}
// @filename: main.js
/** @import { Dog } from "./dog.js" */
const d = new Dog(); // 错误!Try@param 和 @returns
@param 使用与 @type 相同的类型语法,但增加了一个参数名。 参数也可以通过在名称周围添加方括号来声明为可选:
// 参数可以用多种语法形式声明
/**
* @param {string} p1 - 一个字符串参数。
* @param {string=} p2 - 一个可选参数(Google Closure 语法)
* @param {string} [p3] - 另一个可选参数(JSDoc 语法)。
* @param {string} [p4="test"] - 一个带有默认值的可选参数
* @returns {string} 这是结果
*/
function stringsStringStrings(p1, p2, p3, p4) {
// TODO
}Try同样,对于函数的返回类型:
/**
* @return {PromiseLike<string>}
*/
function ps() {}
/**
* @returns {{ a: string, b: number }} - 可以使用 '@returns' 以及 '@return'
*/
function ab() {}Try@typedef、@callback 和 @param
你可以使用 @typedef 定义复杂类型。 类似的语法也适用于 @param。
/**
* @typedef {Object} SpecialType - 创建一个名为 'SpecialType' 的新类型
* @property {string} prop1 - SpecialType 的一个字符串属性
* @property {number} prop2 - SpecialType 的一个数字属性
* @property {number=} prop3 - SpecialType 的一个可选数字属性
* @prop {number} [prop4] - SpecialType 的一个可选数字属性
* @prop {number} [prop5=42] - 带有默认值的 SpecialType 可选数字属性
*/
/** @type {SpecialType} */
var specialTypeObject;
specialTypeObject.prop3;Try你可以在第一行使用 object 或 Object。
/**
* @typedef {object} SpecialType1 - 创建一个名为 'SpecialType1' 的新类型
* @property {string} prop1 - SpecialType1 的一个字符串属性
* @property {number} prop2 - SpecialType1 的一个数字属性
* @property {number=} prop3 - SpecialType1 的一个可选数字属性
*/
/** @type {SpecialType1} */
var specialTypeObject1;Try@param 允许类似的一次性类型规范语法。 请注意,嵌套的属性名必须用参数名称作为前缀:
/**
* @param {Object} options - 形状与上面的 SpecialType 相同
* @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,但它指定的是函数类型而不是对象类型:
/**
* @callback Predicate
* @param {string} data
* @param {number} [index]
* @returns {boolean}
*/
/** @type {Predicate} */
const ok = (s) => !(s.length % 2);Try当然,所有这些类型都可以在单行 @typedef 中使用 TypeScript 语法声明:
/** @typedef {{ prop1: string, prop2: string, prop3?: number }} SpecialType */
/** @typedef {(data: string, index?: number) => boolean} Predicate */@template
你可以使用 @template 标签声明类型参数。 这使你能够创建泛型函数、类或类型:
/**
* @template T
* @param {T} x - 一个泛型参数,会传递到返回类型
* @returns {T}
*/
function id(x) {
return x;
}
const a = id("string");
const b = id(123);
const c = id({});Try使用逗号或多个标签来声明多个类型参数:
/**
* @template T,U,V
* @template W,X
*/你也可以在类型参数名称之前指定类型约束。 列表中只有第一个类型参数会被约束:
/**
* @template {string} K - K 必须是字符串或字符串字面量
* @template {{ serious(): string }} Seriousalizable - 必须有一个 serious 方法
* @param {K} key
* @param {Seriousalizable} object
*/
function seriousalize(key, object) {
// ????
}Try最后,你可以为类型参数指定默认值:
/** @template [T=object] */
class Cache {
/** @param {T} initial */
constructor(initial) {
}
}
let c = new Cache()Try@satisfies
@satisfies 提供了对 TypeScript 中后缀运算符 satisfies 的访问。Satisfies 用于声明一个值实现了一个类型,但不会影响该值的类型。
// @ts-check
/**
* @typedef {"hello world" | "Hello, world"} WelcomeMessage
*/
/** @satisfies {WelcomeMessage} */
const message = "hello world"
/** @satisfies {WelcomeMessage} */const failingMessage = "Hello world!"
/** @type {WelcomeMessage} */
const messageUsingType = "hello world"
Try类
类可以声明为 ES6 类。
class C {
/**
* @param {number} data
*/
constructor(data) {
// 属性类型可以被推断
this.name = "foo";
// 或者显式设置
/** @type {string | null} */
this.title = null;
// 或者仅注释,如果它们在其他地方设置
/** @type {number} */
this.size;
this.initialize(data); // 应该报错,初始化器期望一个字符串
}
/**
* @param {string} s
*/
initialize = function (s) {
this.size = s.length;
};
}
var c = new C(0);
// C 应该只能通过 new 调用,但因为它是 JavaScript,这是允许的,
// 并被视为 'any'。
var result = C(1);Try它们也可以声明为构造函数;为此请使用 @constructor 和 @this。
属性修饰符
@public、@private 和 @protected 的工作方式与 TypeScript 中的 public、private 和 protected 完全相同:
// @ts-check
class Car {
constructor() {
/** @private */
this.identifier = 100;
}
printIdentifier() {
console.log(this.identifier);
}
}
const c = new Car();
console.log(c.identifier);Try@public总是隐含的,可以省略,但意味着属性可以从任何地方访问。@private意味着属性只能在包含它的类中使用。@protected意味着属性只能在包含它的类以及所有派生类中使用,但不能在包含它的类的不相似实例上使用。
@public、@private 和 @protected 在构造函数中不起作用。
@readonly
@readonly 修饰符确保属性仅在初始化期间被写入。
// @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 中相同;在覆盖基类方法的方法上使用它:
在 tsconfig 中设置 noImplicitOverride: true 以检查覆盖。
@extends
当 JavaScript 类扩展一个泛型基类时,没有用于传递类型参数的 JavaScript 语法。@extends 标签允许这样做:
注意 @extends 只适用于类。目前,没有一种方法可以使构造函数扩展一个类。
@implements
同样,没有用于实现 TypeScript 接口的 JavaScript 语法。@implements 标签的工作方式与 TypeScript 中一样:
@constructor
编译器根据 this 属性的赋值来推断构造函数,但如果你添加一个 @constructor 标签,可以使检查更严格,建议更好:
/**
* @constructor
* @param {number} data
*/
function C(data) {
// 属性类型可以被推断
this.name = "foo";
// 或者显式设置
/** @type {string | null} */
this.title = null;
// 或者仅注释,如果它们在其他地方设置
/** @type {number} */
this.size;
this.initialize(data);}
/**
* @param {string} s
*/
C.prototype.initialize = function (s) {
this.size = s.length;
};
var c = new C(0);
c.size;
var result = C(1);Try使用 @constructor,this 在构造函数 C 内部会被检查,因此你会得到 initialize 方法的建议,如果你传递一个数字给它,会出现错误。如果你调用 C 而不是构造它,编辑器也可能会显示警告。
不幸的是,这意味着同时也是可调用的构造函数不能使用 @constructor。
@this
当编译器有一些上下文可以处理时,它通常可以推断出 this 的类型。当它不能时,你可以用 @this 显式指定 this 的类型:
/**
* @this {HTMLElement}
* @param {*} e
*/
function callbackForLater(e) {
this.clientHeight = parseInt(e); // 应该没问题!
}Try文档
@deprecated
当一个函数、方法或属性被弃用时,你可以通过用 /** @deprecated */ JSDoc 注释标记来让用户知道。该信息会显示在补全列表中,并作为建议诊断信息,编辑器可以特殊处理。在像 VS Code 这样的编辑器中,弃用的值通常以删除线样式显示 像这样。
@see
@see 允许你链接到程序中的其他名称:
一些编辑器会将 Box 转换为链接,使其易于跳转和返回。
@link
@link 类似于 @see,但它可以在其他标签内部使用:
type Box<T> = { t: T }
/** @returns 一个包含参数的 {@link Box}。 */
function box<U>(u: U): Box<U> {
return { t: u };
}Try你也可以链接一个属性:
type Pet = {
name: string
hello: () => string
}
/**
* 注意:你应该实现 Pet 的 {@link Pet.hello} 方法。
*/
function hello(p: Pet) {
p.hello()
}Try或带有可选名称:
type Pet = {
name: string
hello: () => string
}
/**
* 注意:你应该实现 Pet 的 {@link Pet.hello | hello} 方法。
*/
function hello(p: Pet) {
p.hello()
}Try其他
@enum
@enum 标签允许你创建一个对象字面量,其成员都是指定类型。与 JavaScript 中的大多数对象字面量不同,它不允许其他成员。 @enum 旨在与 Google Closure 的 @enum 标签兼容。
/** @enum {number} */
const JSDocState = {
BeginningOfLine: 0,
SawAsterisk: 1,
SavingComments: 2,
};
JSDocState.SawAsterisk;Try注意 @enum 与 TypeScript 的 enum 有很大不同,且简单得多。然而,与 TypeScript 的枚举不同,@enum 可以有任何类型:
/** @enum {function(number): number} */
const MathFuncs = {
add1: (n) => n + 1,
id: (n) => -n,
sub1: (n) => n - 1,
};
MathFuncs.add1;Try@author
你可以使用 @author 指定项目的作者:
请记住用尖括号将电子邮件地址括起来。 否则,@example 将被解析为一个新标签。
其他支持的模式
var someObj = {
/**
* @param {string} param1 - 属性赋值上的 JSDoc 也有效
*/
x: function (param1) {},
};
/**
* 变量赋值上的 JSDoc 也有效
* @return {Window}
*/
let someFunc = function () {};
/**
* 以及类方法
* @param {string} greeting 要使用的问候语
*/
Foo.prototype.sayHi = (greeting) => console.log("Hi!");
/**
* 以及箭头函数表达式
* @param {number} x - 一个乘数
*/
let myArrow = (x) => x * x;
/**
* 这意味着它也适用于 JSX 中的函数组件
* @param {{a: string, b: number}} props - 一些参数
*/
var fc = (props) => <div>{props.a.charAt(0)}</div>;
/**
* 参数可以是一个类构造函数,使用 Google Closure 语法。
*
* @param {{new(...args: any[]): object}} C - 要注册的类
*/
function registerClass(C) {}
/**
* @param {...string} p1 - 一个 'rest' 参数(数组),包含字符串。(被视为 'any')
*/
function fn10(p1) {}
/**
* @param {...string} p1 - 一个 'rest' 参数(数组),包含字符串。(被视为 'any')
*/
function fn9(p1) {
return p1.join();
}Try不支持的模式
对象字面量类型中属性类型上的后缀等号并不指定可选属性:
/**
* @type {{ a: string, b: number= }}
*/
var wrong;
/**
* 而是在属性名称上使用后缀问号:
* @type {{ a: string, b?: number }}
*/
var right;Try可空类型只有在 strictNullChecks 开启时才有意义:
/**
* @type {?number}
* 启用 strictNullChecks: true -- number | null
* 启用 strictNullChecks: false -- number
*/
var nullable;TryTypeScript 原生语法是联合类型:
/**
* @type {number | null}
* 启用 strictNullChecks: true -- number | null
* 启用 strictNullChecks: false -- number
*/
var unionNullable;Try非空类型没有意义,仅被视为其原始类型:
与 JSDoc 的类型系统不同,TypeScript 只允许你将类型标记为包含 null 或不包含。没有明确的非空性——如果 strictNullChecks 开启,那么 number 不可为空。如果关闭,则 number 可为空。
不支持的标签
TypeScript 忽略任何不支持的 JSDoc 标签。
以下标签有支持它们的开放问题:
@memberof(issue #7237)@yields(issue #23857)@member(issue #56674)
旧版类型同义词
许多常见类型为与旧 JavaScript 代码兼容而赋予了别名。 一些别名与现有类型相同,尽管其中大多数很少使用。 例如,String 被视为 string 的别名。 尽管 String 是 TypeScript 中的一种类型,但旧的 JSDoc 经常用它来表示 string。 此外,在 TypeScript 中,原始类型的大写版本是包装类型——使用它们几乎总是一个错误。 因此,编译器根据旧 JSDoc 中的用法将这些类型视为同义词:
String -> stringNumber -> numberBoolean -> booleanVoid -> voidUndefined -> undefinedNull -> nullfunction -> Functionarray -> Array<any>promise -> Promise<any>Object -> anyobject -> any
当 noImplicitAny: true 时,最后四个别名被关闭:
object和Object是内置类型,尽管Object很少使用。array和promise不是内置类型,但可能在你的程序中的某处声明。