前言
此前,笔者介绍写过一篇博文,介绍的是关于 JavaScript 原生Typing提案的事情。本篇给大家科普一下另外一个JavaScript可用的类型标记工具: JSDoc。
许多开发人员喜欢使用 TypeScript,因为它具有类型检查功能。然而在打包期间需要额外的转译步骤,既麻烦又浪费时间。本文将向您介绍如何使用 JSDoc 来获取所有相同类型的控件,但只需编写纯 JavaScript 即可,这样不仅能缩短开发时间,还能获得更好的文档!
JavaScript 已成为近来使用最多的脚本语言之一。它以易于在网络平台上编写脚本而闻名。随着JavaScript语言的发展,它已从Java成功时的"玩具"语言发展成为一门成熟的语言,不仅可用于编写小脚本,还可用于编写更多脚本。久而久之,JavaScript本身的缺陷也越来越明显,其中包括:
- 缺乏静态类型和严格的类型检查:Javascript 是一种灵活的语言,可以将参数传递到不接受参数的函数中,也可以省略必填值等等。但是在静态类型语言的世界中是不会出现这种情况,因为它会在编译时出错。所以这个"特性"也给基于Javascript开发的应用程序带来了很多意料之外的问题。
- 难以扩展和维护大型代码库:JavaScript 没有提供强大的机制来管理大型代码库,因此随着时间的推移,项目的扩展和维护都将面临巨大的挑战。
JavaScript的救星:TypeScript
2014 年,微软推出了 Typescript v1.0,谁曾想过浙江改变整个 JavaScript 生态系统。作为 JavaScript 的超集,TypeScript 解决了上述问题以及更多问题。这使得它在近代也越来越受欢迎。
2022年JS状态调查显示,TypeScript 的使用率在上升。 然而TypeScript 虽然解决了很多问题,但也有其缺点。
在本文中,我们将介绍 TypeScript 的一个很好的替代方案JSDoc,它在解决静态类型和可扩展性问题的同时,也消除了 TypeScript 在 JavaScript 生态系统中的这些缺点。
JSDoc为何物?
JSDoc 是 JavaScript 的文档系统,它的工作方式很简单,就是通过一定格式的注释来让编辑器来识别并自动将 描述的类型 引用到编码中,目前主流的浏览器都支持JSDoc,所以请放心食用!本质上是借用了编辑器自身的能力。
JSDoc vs Typescript
JSDoc 和 TypeScript 都解决了编写和维护纯 JavaScript 代码的问题。不过,它们各自采用了不同的方法,但各有利弊。
JSDoc 相对于 Typescript 的优势:
- 灵活性和兼容性:JSDoc 只是 JavaScript 注释,这意味着它可以添加到任何 JavaScript 代码库中,无论语言版本如何,而且不像 TypeScript 那样与编译器绑定。
- 代码注释JSDoc 不仅仅可用于类型检查。它可用于添加更多文档、描述函数如何工作以及生成文档网站,所有这些都为提高代码的可维护性和理解性提供了价值。
- 无编译步骤:这是从 TypeScript 转向 JSDoc 的最重要原因之一。TypeScript 需要编译才能将 Typescript 代码转换为 Javascript,这样浏览器才能理解它,而 JSDoc 则不需要任何其他步骤,因为它们只是 "注释",这是 Javascript 本身支持的功能。与每次进行更改时都使用必要的 Typescript 构建管道相比,这可以简化开发工作流程并提高速度。
使用 JSDoc 的缺点
虽然 JSDoc 与 TypeScript 相比有很多优势,但随着时间的推移,Typescript 的使用也在不断增加。以下是 Typescript 相对于 JSDoc 的一些优势:
- 更强的静态类型:TypeScript 为类型提供了一个强大的模型,并能在编译时捕捉这些错误。与 JSDoc 不同的是,在 JSDoc 中,这些类型是在代码本身中结束的,并不强制执行。
- 类型推断TypeScript 可以根据值推断类型。这有助于减少显式类型注解,减少代码冗长。
- 反编译TypeScript 可以利用其 polyfill 功能采用 JavaScript 语言的最新和未来功能。它能有效地将这些代码转换为可理解的版本,以适用于尚未支持这些功能的浏览器。
如何使用JSDoc
JSDoc 目前在所有现代编辑器中都得到了广泛的支持,开箱即可享用,无需安装任何插件。
给代码块添加说明
如前所述,JSDoc本质上只是一段特定格式的注释
js
/** The name of the language JSDoc is written for **/
const language = "JavaScript"
给值添加类型标记
js
/**
* This represents the writer of this blog
* @type {string}
*/
const writerName = "Dev Flow"
最终编辑器的效果如下,已经自动识别成字符串并且给出相关方法提示:
就问你,爽不爽?
复杂对象的类型标记
数组
js
/**
* @type {Array<string>}
*/
const colours = ['red', 'blue', 'green']
/**
* @type {number[]}
*/
const primeNumbers = [1, 2, 3, 5, 7]
对象
使用 @typedef
指令可以创建对象类型。
js
/**
* @typedef {Object} User - 用户模型
* @property {number} id
* @property {string} username
* @property {string} email
* @property {[number]} postLikes
* @property {[string]} friends
*/
使用 @type
指定对一个对象进行标记
js
/** @type {User} */
const person1 = {
id: 847,
username: "Elijah",
email: "elijah@user.com",
postLikes: [44, 22, 24, 39],
friends: ["fede", "Elijah"],
};
效果如下:
函数(入参、返回值和预期错误类型)
js
/**
* 两个数字相除
* @param {number} dividend - 被除数
* @param {number} divisor - 除数
* @returns {number} 返回值
*/
function divideNumbers(dividend, divisor) {
return dividend / divisor;
}
@param
关键字后面定义了一个类型,表示所定义的函数将接受的值。您还可以在连字符(-)后添加一些参数描述。@returns
关键字用于定义函数的返回值。这对大型函数尤其有用。可能很难通过所有代码(包括早期返回)来确定函数的预期返回值。
此外我们还可以使用 @throws
指令添加函数可能抛出的错误。在改进除法函数时,我们可以指定如果被除数为零,函数将返回错误,并在代码本身中进行处理。
js
/**
* 两个数字相除
* @param {number} dividend - 被除数
* @param {number} divisor - 除数
* @returns {number} 返回值
* @throws {ZeroDivisionError} 除数不可以为0
*/
function divideNumbers(dividend, divisor) {
if (divisor === 0) {
throw new DivisionByZeroError('Cannot Divide by zero')
}
return dividend / divisor;
}
Class类
js
/**
* 矩形类
* @class
* @classdec 一个具有相等长度的对边和四个直角的四边形
*/
class Rectangle {
/**
* 初始化矩形对象。
* @param {number} length - 矩形的长度。
* @param {number} width - 矩形的宽度。
*/
constructor(length, width) {
this.length = length;
this.width = width;
}
/**
* 计算矩形的面积。
* @returns {number} 矩形的面积。
*/
calculateArea() {
return this.length * this.width;
}
/**
* 计算矩形的周长。
* @returns {number} 矩形的周长。
*/
calculatePerimeter() {
return 2 * (this.length + this.width);
}
}
上面是一个简单的矩形类,包含了两个计算面积和周长的方法。
@class
关键字用于表示需要使用 new 关键字调用一个函数。@classdec
用于描述整个类。@params
关键字为需要传入构造函数的参数提供类型和说明
在对类对象进行类型标记时,最重要的是要将粒度细到 构造函数
以及 类中创建的所有方法和变量
。
将JSDoc导出为文档
使用 JSDoc 的最大好处之一是可以将 JSDoc 文件转换为文档网站,甚至转换为 Typescript,这样就可以获得使用 Typescript 的好处,如在编译时捕捉错误、与 Typescript 项目集成等。
从 JSDoc 文件生成文档
安装JSDoc
js
npm install -g jsdoc
指定目标文件运行 jsdoc
js
jsdoc path/to/file.js
查阅文档
jsdoc CLI 会自动创建一个存放文件的 out 文件夹,转到 out/index.html 双击用浏览器打开 这仅仅是默认的jsdoc生成文档的模板,我们也可以对模板进行不同的配置。
从 JSDoc 生成 .d.ts 文件
TypeScript 中的 .d.ts 文件代表声明文件,其中包含可被项目中所有 .ts 文件访问的类型。咱可以使用以下步骤从 JSDoc 代码生成这些文件:
在文件夹中安装 tsd-jsdoc
js
npm install tsd-jsdoc
生成 .d.ts 文件
对于单个文件
js
jsdoc -t node_modules/tsd-jsdoc/dist -r our/jsdoc/file/path.js
对于多个文件
js
jsdoc -t node_modules/tsd-jsdoc/dist -r file1.js file2.js file3.js ...
对于整个文件夹
js
jsdoc -t node_modules/tsd-jsdoc/dist -r src
该工具将文件中的所有类型合并到 out/types.d.ts 中的一个文件中。
注意:前提是已经安装了上一小节中的 jsdoc。如果没有,请先安装后再运行此步骤。
结语
至此,我们已经学会了如何使用JSDoc来生成类型和文档,并且了解了JSDoc的基本用法。JSDoc在以下情况特别有用:当你的TypeScript编译时间/构建步骤对生产力产生负面影响时,它可以发挥特别大的作用。此外在处理旧代码库时非常有用,因为不需要引入任何第三方工具,只要加亿点点注释就好了!