TypeScript 的注释就是 JavaScript 的注释:// 注释掉一行中剩下的部分,/* */ 注释一整块。以 /** 开头的块注释是文档注释(JSDoc),当你把鼠标悬停在它所描述的东西上时,编辑器会显示它。除此之外,TypeScript 还会读取几种特殊注释,它们会改变编译器检查代码的方式。
输出:
212
注释不会影响程序运行。除了下文介绍的指令注释,它们也不会影响类型检查。
单行注释和块注释
// 会注释掉这一行中它后面的所有内容,这也是临时禁用一行代码的快捷方式。/* */ 可以放在一行的中间,也可以覆盖很多行。
块注释不能嵌套。第一个 */ 就会结束注释,所以把已经包含块注释的代码再包起来就会出错:
/* outer comment /* inner comment */ this text is now code */
编译器接着会把 this text is now code */ 当作代码来读,并报告语法错误。要注释掉一段含有块注释的代码,请在每行前加 //;大多数编辑器用 Ctrl+/(macOS 上是 Cmd+/)就能完成。
JSDoc 文档注释
紧挨在函数、类、方法、属性、接口或变量前面的 /** ... */ 注释就是它的文档。编辑器会在悬停提示和自动补全中显示其文字,TypeDoc 等文档生成工具会把它变成参考页面。TSDoc 是 Microsoft 发起的 TypeScript 代码注释标准,常用标签的语法与 JSDoc 相同:
| 标签 | 含义 |
|---|---|
@param name description | 描述一个参数 |
@returns description | 描述返回值 |
@throws description | 描述函数可能抛出的错误 |
@example | 开始一个示例块,后面通常跟一个代码块 |
@deprecated reason | 把 API 标记为已弃用;编辑器会给它加上 |
@see 或 {@link Name} | 指向相关代码 |
@remarks | 摘要行之后更详细的说明 |
在 .ts 文件中,不要在 JSDoc 里重复写类型。代码中的注解才是类型,JSDoc 类型标签在这里会被忽略:/** @type {string} */ const v: number = 5; 能毫无怨言地通过编译,因为只有 : number 算数。
在编辑器中,在项目里任何地方把鼠标悬停在 transfer 或 balance 上,都会显示这些说明。
把代码标记为已弃用
@deprecated 不会导致编译错误。它让编辑器把已弃用函数的每一处使用都显示为删除线,并在悬停时显示原因,这是引导调用者改用替代方案的温和方式:
输出:
$19.99
19.99 EUR
@ts-expect-error 和 @ts-ignore
这两种注释会屏蔽紧随其后那一行的类型错误。有时这样做是对的:比如测试某个函数在运行时如何处理错误输入,或者某个库的类型存在已知缺陷。
输出:
runtime error: text.toUpperCase is not a function
没有这条注释,shout(42) 是一个编译错误(TS2345)。加上它之后,文件可以编译,调用也能执行到运行时,这正是这个测试的目的。
两种指令的区别在错误消失时才会显现。@ts-expect-error 坚持那里必须有错误可屏蔽,所以一条过时的注释本身就会变成错误:
index.ts(6,1): error TS2578: Unused '@ts-expect-error' directive.
把同样位置换成 // @ts-ignore,不管错误存在还是已经消失,它都不会出声。这就是为什么 @ts-expect-error 是更好的默认选择:当有人修复了类型时,编译器会告诉你这条屏蔽可以删掉了。始终像上面的示例那样在指令后面写上原因,让下一个读代码的人知道它为什么存在。
两者都只作用于下一行,并屏蔽这一行上的所有错误。如果要整体绕过某个值的类型,显式的 as unknown as T 或运行时检查通常比屏蔽注释更清晰。
@ts-nocheck 和 @ts-check
文件顶部的 // @ts-nocheck 会关闭整个文件的类型检查。它必须放在最前面、任何代码之前:放在后面会被忽略,错误依然会出现。
// @ts-nocheck
const n: number = "not a number"; // no error reported
它在迁移大型 JavaScript 代码库时很有用,在其他场合则是一种坏味道。
// @ts-check 在 JavaScript 文件中的作用正好相反:即使 tsconfig.json 中关闭了 checkJs,它也会为这个 .js 文件开启类型检查,依据是类型推断和 JSDoc 类型(这个文件仍然需要通过 allowJs 成为项目的一部分):
// @ts-check
/**
* @param {number} cents
* @returns {string}
*/
function formatCents(cents) {
return (cents / 100).toFixed(2);
}
formatCents("12"); // error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
在 JavaScript 文件中,JSDoc 标签就是类型,很多项目正是靠这种方式在不把文件转成 .ts 的情况下获得类型检查。
三斜线指令
文件最顶部形如 /// <reference ... /> 的注释是一条编译器指令:
/// <reference types="node" />
/// <reference lib="es2023.array" />
/// <reference path="./globals.d.ts" />
types="node"把一个@types包加入程序,就像在tsconfig.json的"types"中列出它一样。lib="..."把一个内置库加入程序,就像lib选项一样。path="..."引入另一个文件,主要在.d.ts文件中使用。
在应用代码中,import 语句和 tsconfig.json 设置几乎可以取代它们的所有用途;你主要会在声明文件和生成的代码中遇到这些指令,比如 Vite 的 vite-env.d.ts。来看一个简单的演示,lib 让这个文件可以使用一个较新的数组方法:
编译输出中的注释
tsc 会把注释保留在它生成的 JavaScript 中。设置 "removeComments": true 可以删除注释;即便如此,以 /*! 开头的注释仍会保留,这是许可证头部的惯例写法:
/*! MyLib v1.2.0 | MIT License */
开启 declaration 时,JSDoc 注释也会被复制到 .d.ts 文件中,这样库的使用者在编辑器里就能看到这些说明。
常见问题
TypeScript 中如何写注释?
和 JavaScript 一样:// 开始一条直到行尾的注释,/* ... */ 包裹可以跨越多行的注释。以 /** 开头的块注释是文档注释(JSDoc),当你把鼠标悬停在被注释的函数、类或属性上时,编辑器会显示它。
@ts-ignore 和 @ts-expect-error 有什么区别?
两者都会屏蔽下一行的类型错误。// @ts-expect-error 还会检查那里确实有错误:如果那一行不再出错,编译器会报告 error TS2578: Unused '@ts-expect-error' directive.,这样过时的屏蔽就会被发现。// @ts-ignore 则永远保持沉默。优先使用 @ts-expect-error。
如何忽略整个文件的 TypeScript 错误?
在文件顶部、任何代码之前加上 // @ts-nocheck。编译器就不会再为这个文件报告类型错误(语法错误仍会出现)。它是迁移用的工具;只想屏蔽一行时,请改用 // @ts-expect-error。
注释会保留在编译出的 JavaScript 中吗?
会,tsc 默认在输出中保留注释。设置 "removeComments": true 后会删除注释,但以 /*! 开头的注释除外,它们会保留下来,用于许可证头部。打包工具和压缩工具通常会在生产构建中去掉注释。
在 .ts 文件里应该用 JSDoc 注释写类型吗?
不应该。在 .ts 文件中,@type {string} 或 @param {number} x 这类 JSDoc 类型标签不参与类型检查;代码里的注解才是类型。在 .ts 文件中用 JSDoc 写说明文字,只在用 // @ts-check 或 checkJs 检查的 .js 文件里用 JSDoc 写类型。