使用背景
在很多存量的项目中,可能很多项目都没有上ts,以及开发人员的注释写的云里雾里。比如以下场景,当你接手这种代码时,你会不会跟我一样想params
要传什么?这个函数有没有返回值?返回值是什么?
javascript
// 获取用户信息
function getUser (params) {
// code
}
当你跟我有相同的疑问时,我们何妨不花几分钟来了解今天的主角jsdoc
,来优化我们的🪨山代码呢~~
主要关键字使用说明
@typedef
语法: [<type>] <namepath>
使用场景:声明一个自定义类型,可以用于函数入参出参,类型于typesript的type定义
javascript
/**
* @typedef {Object} User
* @property {string} User.name - 用户姓名
* @property {number} User.age - 用户年龄
*/
/**
* @param {User} 查询的用户
* @returns {number} 用户年龄
*/
function getUserAge(user) {
return user.age
}
效果:调用函数就会根据定义的类型来进行智能推断
@enum
语法:@enum <type>
使用场景:定义一个对象为枚举类型,可以直接使用该对象作为入参类型,一般配合@readonly使用,因为枚举值正常来说是不能被更改的。
javascript
/**
* @readonly
* @enum {'1' | '2'}
*/
const SEX = {
MALE: '1',
FEMALE: '2',
}
@callback
语法:@callback <namepath>
使用场景:定义回调函数的类型,以充当其他函数的入参类型。 比单纯使用Function
类型来定义入参会更加的清晰知道回调函数需要几个入参,以及出参。
javascript
/**
* 过滤特定年龄用户回调函数
* @callback RequestUserFilterCallback
* @param {User[]} users 用户数组
* @param {number} limitAge 年龄条件
* @returns {User[]} 符合条件的用户
*/
/**
* 获取用户
* @param {RequestUserFilterCallback} cb 过滤函数
*/
async function fetchUser (cb) {
const users = await fetch('get/users')
return cb(users, 18)
}
fetchUser((users, limitAge) => users.age <= limitAge)
效果:调用函数的时候就会有对应的回调类型提示
@param
语法:@param [<type>] <name> [<description>]
使用场景:建议每个函数的入参都使用@param来进行标注,不仅可以使开发者清晰地知道每个入参的意义,而且在使用函数的时候编辑器也会有对应的类型提示。
必填参数使用示例
javascript
// 这里的类型可以使用javascript的基本类型或者自定义类型
/**
* @readonly
* @enum {'1' | '2'}
*/
const SEX = {
MALE: '1',
FEMALE: '2',
}
/**
* 自定义用户类型
* @typedef {Object} User
* @property {string} User.name - 用户姓名
* @property {number} User.age - 用户年龄
*/
/**
* 给用户增加性别
* @param {User} user 查询的用户
* @param {SEX} sex 用户性别
* @returns {User & {sex: SEX}} 具有性别属性的用户
*/
function addUserSex(user, sex) {
return {...user, sex}
}
效果:写好函数入参,出参的类型标注,编辑器会获得类型提示,减少开发理解和使用成本。
可选参数使用示例
给参数增加[],代表可选参数
javascript
/**
* 获取用户性别
* @param {User} [user] 查询的用户,可能为空
* @returns {SEX | null}
*/
function getUserSex (user) {
if (user) {
return user.sex
}
return null
}
getUserSex()
效果:
@this
语法:@this 声明的对象
使用场景:声明当前函数的this指向,在非纯函数的编程环境中,this的指向经常是编辑器无法推断的,而且对其他开发人员也不够清晰,使用@this可以清晰地告诉外界当前函数的this指向
javascript
/**
* @description jsdoc this 使用示例
* @this Vue
*/
function testThis () {
this.$alert('123')
}
效果:此时调用函数时编辑器会识别并且有智能提醒
@todo
语法:@todo 描述要实现的事情
使用场景:当版本功能还未完成时,用@todo
标记后续待实现的功能。
javascript
/**
* 实现一个使用例子
* @todo 增加例子
* @todo 增加注释
*/
function createExample () {}
@example
使用场景:给函数增加使用例子,特别是参数较多的函数,建议多种情况的例子都标注好。
javascript
/**
* 两数相加
* @param {number} num1 相加数字
* @param {number} num2 相加数字
* @returns {number} 两数之和
* @example
* add(1, 2) // 3
*/
function add (num1, num2) {
return num1 + num2
}
效果:调用函数的时候可以看到标注的例子如何进行使用
@deprecated
语法:@deprecated [废弃的原因及指引]
使用场景:当版本升级后,原有代码需要逐步替换时,标注好什么代码在日后不使用以及指引如何切换到新代码,对于版本升级/重构代码时可让团队开发人员清晰知道被标注的代码已废弃。
javascript
/**
* @deprecated 从版本1.0后废弃,登录功能请使用loginV2函数
*/
function login () {}
效果:调用被标注的内容时,编辑器会自动识别到该方法已废弃,并且展示废弃的指引内容。
总结
使用jsdoc有以下的优势
- 提高代码的可读性,提高项目代码可维护性
- 可以在不引入typescript的同时,使用typescript的类型标注,代码静态提示等功能,这在一些老项目的时候非常实用
- 对项目代码无副作用,例如运行构建变慢,代码改造等都无需担心
- 配合现代编辑器可以有很好的智能提醒,减少因手写错误等低级错误的产生
注意事项
- jsdoc并不能代替typescript的功能,它只是一个规范的约束,并不能保证类型安全。
- 建议公用代码及公用组件一定要进行良好的类型标注及例子说明。
上述例子只是列举来一些比较常用的场景,还有更多深入的玩法可以参考jsdoc官方网站。