[译] 使用纯 JavaScript 获得完整的类型支持
这听起来很熟悉:你想写一个小脚本,不论是为了网页、命令行工具还是其他用途,一开始你选择使用JavaScript...直到你记起在没有类型的情况下编写代码有多痛苦。于是,你将文件的扩展名从.js改为.ts...结果你发现自己引开了一个潘多拉魔盒。
如果你在为网站或库编写代码,就需要添加一个编译步骤。如果你正在构建一个CLI脚本,你可以使用 Deno(它原生支持TypeScript),但是你需要设置你的IDE以理解Deno
的API,而且在 Deno
和 Node 之间混合使用并不总是容易。
一旦在本地使一切都运行良好,你需要考虑如何分发你的代码。你是否检入已编译的.js
文件?你是否创建一个CI流水线来自动编译.ts
文件?如果你正在编写一个库,你如何发布它以便其他项目可以使用?
你实际上并不需要 TypeScript
问题是……你不需要为了获得静态类型分析而编写 TypeScript!
通过使用 JSDoc,您可以在 JavaScript 中获得 TypeScript 的所有好处。
TypeScript 提供的是静态类型系统。这意味着类型信息在运行代码时没有任何效果。当你执行 TypeScript 代码时,所有的类型信息都会完全丢失(这也是为什么你不能在不编写类型保护的情况下测试变量是否属于某种类型的原因)。
这也意味着 TypeScript 只是提供给 TypeScript 分析器的附加类型信息,对于运行你的代码的 JavaScript 引擎来说没有任何意义。当你将 TypeScript 编译为 JavaScript 时,它基本上只是从代码中删除了所有的类型信息,使其重新成为有效的 JavaScript 代码。
JSDoc
在 JavaScript 诞生25年后的三年后,JSDoc 被引入作为一种注释 JavaScript 代码的方式。它是一种正式的标记语言,允许 IDE 在开发者查看函数时提供额外的上下文信息。
类似的注释标记在大多数语言中都存在,我相信你已经了解了。下面是它的示例:
/**
* This is the JSDOC block. IDEs will show this text when you hover the
* printName function.
*
* @param {string} name
*/
function printName(name) {
console.log(name)
}
TypeScript 和 JSDoc
很少有人知道的是,只需要 JSDoc,你就可以充分利用 TypeScript。TypeScript 分析器能理解在 JSDoc 中编写的类型,并为你提供与 .ts
文件相同的静态分析。
JSDoc 中的类型语法
我不会在这里提供完整的语法文档。最重要的是,你需要知道,几乎你在 .ts
文件中能做的任何事情,你都可以在 JSDoc 中实现。下面是一些示例:
使用原生类型的函数参数:
/**
- @param {string} a
- @param {number} b
*/
function foo(a, b) {}
使用 TypeScript 开箱即用的类型:
/**
- @param {HTMLElement} element
- @param {Window} window
*/
function foo(element, window) {}
/** @type {number[]} */
let years
定义对象字面量和函数:
/** @type {{ name: string; age: number }} */
let person
/** @type {(s: string, b: boolean) => void} */
let myCallback
从 *.d.ts
文件导入类型:
/** @param {import('./types').User} user */
const deleteUser = (user) => {}
为以后使用定义类型:
/**
- @typedef {object} Color
- @property {number} chroma
- @property {number} hue
*/
/** @type {Color[]} */
const colors = [ { chroma: 0.2, hue: 262 }, { chroma: 0.2, hue: 28.3 } ]
如果你有复杂的类型,你仍然可以创作你的 *.d.ts
文件并将它们导入你的 JSDoc 注释中
请注意,你仍然需要为 TypeScript 设置你的项目(和IDE),并且你需要创建一个带有 compiler options 的tsconfig.json
文件,其中 allowJs 和 checkJs 设置为 true:
// tsconfig.json
{
"compilerOptions": {
"allowJs": true,
"checkJs": true
// ...
}
}
何时使用 TypeScript
虽然仅使用 JSDoc 来进行类型声明是可行的,但并不是最方便的方法。TypeScript 的语法更加美观,而且不那么重复。
TypeScript 团队已经创建了一个名为“Types as comments”
的 ECMAScript 提案,它将允许你编写 TypeScript,并在 JavaScript 引擎中运行而无需修改(JavaScript 引擎将将这些类型注解视为注释)。
但在该提案被接受之前,我们只能选择使用 JSDoc 或 TypeScript 工具链。
因此,目前我的建议是:当你在一个已经有编译步骤的项目中工作时,使用 TypeScript 是没有任何问题的。这包括你想要为生产环境优化你的脚本的典型网站。
但如果你不需要编译步骤,那么使用 JSDoc 类型注释可能更容易。这适用于库和简单的脚本。
(当然,这两种方法都有例外情况。)
转载自:https://juejin.cn/post/7235547967113199653