本文首发「码上花甲」公众号,同时发布到掘金,欢迎关注。
近期社区中不少工具放弃了 TypeScript 转而用上了 JsDoc。
咱不评价这种做法是否值得推荐,但是,有一些项目从一开始就没有使用 TypeScript。这种情况下直接迁移到 TypeScript 成本会很高,那能否用 JsDoc 来“代替” TypeScript 呢?
答案是可行的。
我们不能因为 TS 而一定要用 TS,必须要结合项目实际情况来确定。
不过 JsDoc 也有很多细节,是你可能没注意到的。除了静态类型检查之外,JsDoc 的能力还是蛮强大的。
今天,我们就结合 TS 来看下 JsDoc 都能干哪些事情。
1. 变量的类型
在 TS 中,要给一个变量定义类型很简单:
let name: string = 'Randal';使用 TS,直接在变量 name 后面定义为 string 类型即可。
JsDoc 也能做到:
/** @type {string} */
let name = 'Randal';编辑器同样可以识别出 JsDoc 注释的变量类型:

像其他基本类型,JsDoc 也都支持,比如 number 类型。
/** @type {number} */
let age = 30;除了上面这种简单的基本类型之外,JsDoc 还支持联合类型。在 TS 中的写法是这样的:
const personName: 'Randal' | 'Olive' | 'Jack' = 'Randal';JsDoc 的写法稍微麻烦一点,但也能很好的支持:
/**
* @typedef {'Randal' | 'Olive' | 'Jack'} PersonName
*/
/**
* @type {PersonName}
*/
const personName = 'Randal';同样的,编辑器也能正确识别出对应的类型:

对于普通的变量,在 JsDoc 中可以用 @type 标签描述变量的类型;对于联合类型可借助 @typeof 标签辅助完成。其他的基本类型写法都差不多,就不一一展示了。
2. 函数参数和返回值
函数是 JS 中的一等公民,其重要性不言而喻。我们常见的类型定义一般都见于函数声明。
要使用 JsDoc 给函数参数定义类型,需要用到 param 标签。
比如下面的函数,用 TS 表示是这样的:
// Say hi to someone.
function sayHiSomeone(name: string) {
console.log('Hi ' + name);
}很简单,写法类似于给变量定义类型,直接在函数参数后面给定相应的类型即可,上面的是 string 类型。
JsDoc 的话不难,只不过需要稍微多写一点注释:
/**
* Say hi to someone.
* @param {string} name - the name of somebody(with type and description)
*/
function sayHiSomeone(name) {
console.log('Hi ' + name);
}@param 标签就表示给函数的参数定义类型和描述,{} 中的就是参数 name 的类型,后面的字符串是该参数的描述信息。
鼠标悬停在函数上,会显示函数的类型定义:

而函数的返回值被隐式地定义为了 void 类型。
也对,函数体内确实没有 return 数据出去,说明推断的是正确的。
如果要显式地定义函数返回值该怎么做呢?
/**
* Say hi to someone.
* @param {string} name - the name of somebody(with type and description)
* @return {undefined}
*/
function sayHiSomeone(name) {
console.log('Hi ' + name);
return undefined;
}可以用 @return 标签表示函数的返回值,{} 中定义函数返回值类型:

上面演示的都是简单类型的定义,对于稍微复杂一点的——比如对象类型或数组类型该怎么办呢?
下面是一个 TS 示例:
interface EmployeeType {
name: string;
department: string;
}
function Project() {}
Project.prototype.assignment = function(employee: EmployeeType) {
console.log(employee.name + ' works in ' + employee.department);
};借助 TS 的 interface 很容易就能定义参数 employee 的类型,在 JsDoc 中的写法却有点不一样:
function Project() {}
/**
* 记录参数属性
* @param {Object} employee - the employee for assignment
* @param {string} employee.name - the name of employee
* @param {string} employee.department - the department of employee
*/
Project.prototype.assignment = function(employee) {
console.log(employee.name + ' works in ' + employee.department);
};可以看到第一个 @param 标签的类型是 Object,表示 employee 参数是一个对象类型。
然后,再以此定义这个对象类型中成员的类型,第二个和第三个 @param 标签定义的都是 string 类型。
不过,这里要注意的一点是,@param 标签类型后的 employee 必须要保持和函数参数名一致,编辑器才能识别出来。

数组参数类型的写法是差不多的,比如:
/**
* 记录数组中值的属性
* @param {Object[]} employees - the employees params
* @param {string} employees[].name - the name of employee
* @param {string} employees[].department - the department of employee
*/
Project.prototype.employees = function(employees) {
console.log(employees[0].name + ' works in ' + employees[0].department);
};
还有一种常见的场景,JsDoc 如何表示函数的参数是可选的呢?JsDoc 也考虑到这种情况了,用 [] 将参数名包裹起来就表示该参数是可选的:
/**
* 可选参数
* @param {string} [somebody] - somebody's name
*/
function sayHello(somebody) {
if (!somebody) {
somebody = 'Randal Wang';
}
console.log('Hello ' + (somebody || 'me'));
}如果参数 somebody 没有定义,那么其类型应该是 undefined:

最后,一种常见的场景式函数参数是一个回调函数。回调函数在函数体内被调用:
/**
* 回调函数
* @param {requestCallback} cb - the callback that handles the response
*/
function callback(cb) {
if (typeof cb === 'function') {
cb();
}
}鼠标悬浮在函数上的效果如下:

3. async
async 函数表示该函数是异步的,比如在一个函数体内返回 Promise。用 JsDoc 来描述也不难:
/**
* Download data from specitic url
* @async
* @param {string} url - the url to download data
* @return {Promise<string>} the data from url
*/
async function downloadData(url) {
return new Promise((resolve, _reject) => {
setTimeout(() => {
resolve(`Data from ${url}`);
}, 1000);
});
}效果如下:

4. JsDoc 其他标签
除了上面提到的这几个标签较为常用之外,JsDoc 还提供了很多丰富、使用的标签,比如 @see、@link、@abstract、@description、@todo 等等。
虽然较之 TS 的能力还有不少差距,但是也已经能覆盖大部分场景了。
JsDoc 最大的特点是不会侵入到业务代码中,它是以正常的注释的形式存在的。要知道,我们即便用 TS 也是要写注释的。
所以,如果你的项目本来就是用 JS 写的,不妨先把 JsDoc 用起来。将来有机会的时候,再将其迁移到 TS 不失为一个好的选择。
上面仅仅提供几个代码片段,作为抛砖引玉吧算是。如果你对 JsDoc 其他标签还不熟悉,可以去看看官网的示例,很全面。
也可以参考和今天内容配套的源码,有一些常用标签的代码示例供你参考。
好了,今天的内容就先到这里吧,感谢阅读,下期再见 ;-)
为便于理解,为大家准备了源码以供参考:
$ npm install -g @agelesscoding/cli # 安装公众号配套的 agc 脚手架
$ agc init # 在列表中,选择对应的源码示例,比如 20231001 表示 2023 年 10 月 01 号的文章源码
9 comments
寻找华纳圣淘沙公司开户代理(183-8890-9465薇-STS5099】
华纳圣淘沙官方合作开户渠道(183-8890-9465薇-STS5099】
华纳圣淘沙公司开户代理服务(183-8890-9465薇-STS5099】
华纳圣淘沙公司开户咨询热线(183-8890-9465薇-STS5099】
联系客服了解华纳圣淘沙开户
(183-8890-9465薇-STS5099】
华纳圣淘沙公司开户专属顾问
(183-8890-9465薇-STS5099】
华纳圣淘沙开户步骤详解(183-8890-9465—?薇-STS5099【6011643】
华纳圣淘沙公司开户流程全解析(183-8890-9465—?薇-STS5099【6011643】
华纳圣淘沙公司账户注册指南(183-8890-9465—?薇-STS5099【6011643】
新手如何开通华纳圣淘沙公司账户(183-8890-9465—?薇-STS5099【6011643】
华纳圣淘沙企业开户标准流程(183-8890-9465—?薇-STS5099【6011643】
华纳圣淘沙公司开户:从零到一(183-8890-9465—?薇-STS5099【6011643】
官方指南:华纳圣淘沙公司开户流程(183-8890-9465—?薇-STS5099【6011643】
华纳圣淘沙公司开户流程说明书(183-8890-9465—?薇-STS5099【6011643】
华纳东方明珠客服电话是多少?(▲18288362750?《?微信STS5099? 】
如何联系华纳东方明珠客服?(▲18288362750?《?微信STS5099? 】
华纳东方明珠官方客服联系方式?(▲18288362750?《?微信STS5099?
华纳东方明珠客服热线?(▲18288362750?《?微信STS5099?
华纳东方明珠24小时客服电话?(▲18288362750?《?微信STS5099? 】
华纳东方明珠官方客服在线咨询?(▲18288362750?《?微信STS5099?
华纳东方明珠客服电话是多少?(▲18288362750?《?微信STS5099? 】
如何联系华纳东方明珠客服?(▲18288362750?《?微信STS5099? 】
华纳东方明珠官方客服联系方式?(▲18288362750?《?微信STS5099?
华纳东方明珠客服热线?(▲18288362750?《?微信STS5099?
华纳东方明珠24小时客服电话?(▲18288362750?《?微信STS5099? 】
华纳东方明珠官方客服在线咨询?(▲18288362750?《?微信STS5099?
华纳公司合作开户所需材料?电话号码15587291507 微信STS5099
华纳公司合作开户所需材料?电话号码15587291507 微信STS5099
华纳公司合作开户所需材料?电话号码15587291507 微信STS5099
华纳公司合作开户所需材料?电话号码15587291507 微信STS5099
华纳公司合作开户所需材料?电话号码15587291507 微信STS5099
华纳公司合作开户所需材料?电话号码15587291507 微信STS5099
华纳公司合作开户所需材料?电话号码15587291507 微信STS5099
华纳公司合作开户所需材料?电话号码15587291507 微信STS5099
华纳公司合作开户所需材料?电话号码15587291507 微信STS5099
华纳公司合作开户所需材料?电话号码15587291507 微信STS5099
华纳公司合作开户所需材料?电话号码15587291507 微信STS5099
华纳公司合作开户所需材料?电话号码15587291507 微信STS5099
华纳公司合作开户所需材料?电话号码15587291507 微信STS5099
华纳公司合作开户所需材料?电话号码15587291507 微信STS5099
华纳公司合作开户所需材料?电话号码15587291507 微信STS5099
华纳公司合作开户所需材料?电话号码15587291507 微信STS5099
新车即将上线 真正的项目,期待你的参与coinsrore.com
来踩一下
留下你的主页,互踩互踩 ;-)