注释和文档
JSDoc 与注释
有两种类型的注释,JSDoc(/** ... */)和非 JSDoc 的普通注释(// ...
或 /* ... */)。
- 使用
/** JSDoc */注释编写文档,即代码用户应该阅读的注释。 - 使用
// line comments编写实现注释,即只与代码实现本身相关的注释。
JSDoc 注释可以被工具(如编辑器和文档生成器)理解,而普通注释仅供其他人阅读。
多行注释
多行注释与周围代码保持相同的缩进级别。它们必须使用多个单行注释(//
风格),而不是块注释风格(/* */)。
// 这是
// 可以的/*
* 这应该
* 使用多个
* 单行注释
*/
/* 这应该使用 // */注释不应包裹在由星号或其他字符绘制的框中。
JSDoc 一般形式
JSDoc 注释的基本格式如以下示例所示:
/**
* 多行 JSDoc 文本写在这里,
* 正常换行。
* @param arg 一个用于执行某操作的数字。
*/
function doSomething(arg: number) { … }或者单行示例:
/** 这个简短的 jsdoc 描述了该函数。 */
function doSomething(arg: number) { … }如果单行注释溢出为多行,它必须使用多行风格,/** 和 */ 各占一行。
许多工具从 JSDoc 注释中提取元数据来执行代码验证和优化。因此,这些注释必须格式正确。
Markdown
JSDoc 使用 Markdown 编写,但在必要时可以包含 HTML。
这意味着解析 JSDoc 的工具会忽略纯文本格式,所以如果你这样写:
/**
* Computes weight based on three factors:
* items sent
* items received
* last timestamp
*/它会被渲染成这样:
Computes weight based on three factors: items sent items received last timestamp相反,应该写成 Markdown 列表:
/**
* Computes weight based on three factors:
*
* - items sent
* - items received
* - last timestamp
*/JSDoc 标签
Google 风格允许使用 JSDoc 标签的一个子集。大多数标签必须独占一行,标签位于行首。
/**
* "param" 标签必须独占一行,不能合并。
* @param left 对左参数的描述。
* @param right 对右参数的描述。
*/
function add(left: number, right: number) { ... }/**
* "param" 标签必须独占一行,不能合并。
* @param left @param right
*/
function add(left: number, right: number) { ... }行换行
换行的块标签缩进四个空格。换行的描述文本可以与前几行的描述对齐,但不鼓励这种水平对齐。
/**
* 演示长 param/return 描述的换行。
* @param foo 这是一个描述特别长的参数,
* 一行放不下。
* @return 返回的内容描述也太长,
* 一行放不下。
*/
exports.method = function(foo) {
return 5;
};换行 @desc 或 @fileoverview 描述时不要缩进。
为模块的所有顶级导出编写文档
使用 /** JSDoc */
注释向代码的用户传达信息。避免仅仅重述属性或参数名称。你还应该为所有目的不能从其名称中立即看出的属性和方法(导出/公开的或非导出/公开的)编写文档,由审查者判断。
**例外:**仅为了被工具消费而导出的符号(例如 @NgModule 类)不需要注释。
类注释
类的 JSDoc 注释应该为读者提供足够的信息,以了解如何以及何时使用该类,以及正确使用该类所需的任何额外注意事项。构造函数的文本描述可以省略。
方法和函数注释
如果方法、参数和返回值的描述从方法 JSDoc 的其余部分或方法名称和类型签名中显而易见,则可以省略。
方法描述以动词短语开头,描述方法的功能。这个短语不是祈使句,而是以第三人称书写,就好像前面有一个隐含的“此方法…”。
参数属性注释
参数属性(Parameter
Property) 是以修饰符
private、protected、public 或 readonly
为前缀的构造函数参数。参数属性同时声明了一个参数和一个实例属性,并隐式地将参数赋值给它。例如,constructor(private readonly foo: Foo)
声明构造函数接受一个参数 foo,同时也声明了一个私有只读属性
foo,并在执行构造函数的其余部分之前将参数赋值给该属性。
要为这些字段编写文档,请使用 JSDoc 的 @param
注解。编辑器会在构造函数调用和属性访问时显示描述。
/** 此类演示了如何为参数属性编写文档。 */
class ParamProps {
/**
* @param percolator 用于冲泡的过滤器。
* @param beans 要冲泡的咖啡豆。
*/
constructor(
private readonly percolator: Percolator,
private readonly beans: CoffeeBean[]) {}
}/** 此类演示了如何为普通字段编写文档。 */
class OrdinaryClass {
/** 将在下次调用 brew() 时使用的咖啡豆。 */
nextBean: CoffeeBean;
constructor(initialBean: CoffeeBean) {
this.nextBean = initialBean;
}
}JSDoc 类型注解
在 TypeScript 源代码中,JSDoc 类型注解是冗余的。不要在 @param 或
@return 块中声明类型,不要在使用
implements、enum、private、override 等关键字的代码上写
@implements、@enum、@private、@override 等。
编写真正有信息量的注释
对于非导出符号,有时函数或参数的名称和类型就足够了。但代码通常会受益于比仅仅变量名更多的文档!
-
避免仅仅重述参数名称和类型的注释,例如
/** @param fooBarService Foo 应用的 Bar 服务。 */ -
由于此规则,
@param和@return行仅在添加信息时才需要,否则可以省略。/** * 发送请求以开始冲泡咖啡。 * @param amountLitres 要冲泡的量。必须适合壶的大小! */ brew(amountLitres: number, logger: Logger) { // ... }
调用函数时的注释
当方法名称和参数值不足以传达参数的含义时,应使用”参数名”注释。
在添加这些注释之前,考虑重构方法以接受一个接口并解构它,以大大提高调用处的可读性。
“参数名”注释放在参数值之前,包含参数名称和 = 后缀:
someFunction(obviousParam, /* shouldRender= */ true, /* name= */ 'hello');现有代码可能使用旧式的参数名注释风格,将这些注释放在参数值之后并省略
=。在文件中为了保持一致性继续使用这种风格是可以接受的。
someFunction(obviousParam, true /* shouldRender */, 'hello' /* name */);将文档放在装饰器之前
当类、方法或属性同时有装饰器(如 @Component)和 JSDoc 时,请确保将
JSDoc 写在装饰器之前。
-
不要在装饰器和被装饰的语句之间写 JSDoc。
@Component({ selector: 'foo', template: 'bar', }) /** 打印 "bar" 的组件。 */ export class FooComponent {} -
在装饰器之前写 JSDoc 块。
/** 打印 "bar" 的组件。 */ @Component({ selector: 'foo', template: 'bar', }) export class FooComponent {}