JSDoc 让JS有类型约束

这次我们来谈谈JSDoc,首先这是个啥,本质就是个注释,可以帮助开发工具认识你的代码。你可以通过它提升开发效率、降低运行时的错误率,更好的理解强类型语言。

主流编辑器应该都支持JSDoc,但我基本没用过别的所以不太清楚,本文章中演示用的编辑器均为vscode

JS中的类型

js中,虽然类型的概念没那么强,但你依然无时无刻不在受到类型约束

比如最简单的document.querySelector

它会返回一个Element类型的数据,页面元素的基础类型HTMLElement就继承了该类型

但这时如果你想修改style,你会发现它并不会给你提示,因为styleHTMLElement的属性

JS Doc

这时候,JSDoc就派上用场了。在你明确知道它类型的情况下,你可以直接声明变量的类型

1
2
3
4
/**
* @type {HTMLElement}
*/
const test = document.querySelector('.test')

此时再看代码提示,就出现了

并且你可以开启类型检查

1
2
3
4
5
// @ts-check
/**
* @type {HTMLElement}
*/
const test = document.querySelector('.test')

此时如果你写的代码不规范,语法检查就会报错

这样就可以在运行前排除掉大部分因为粗心导致的问题

常用字段

@type

声明变量类型,类型写在{}

1
2
3
4
/**
* @type {string}
*/
const str = 'string'

对象类型不能省略{}

1
2
3
4
5
6
7
8
9
10
/**
* @type {{
* name: string
* age: number
* info: {
* id: number
* }
* }}
*/
const test = {}

@typedef

声明一个自定义类型,配合@type使用,你可以在类型后面起个类型名称

1
2
3
4
5
6
7
8
9
10
11
12
/**
* @typedef {{
* status: number
* message: string
* data: {[key: string]: any}
* }} ResultData
*/

/**
* @type {ResultData}
*/
const test = {}

@param

声明函数形参

1
2
3
4
5
6
7
8
/**
* 加法
* @param {number} n1
* @param {number} n2
*/
function sum(n1, n2) {
return n1 + n2
}

@template

声明一个泛型,泛型相当于是一个类型的变量,我们最常用的数组,就用到了泛型Array<T>

如果定义Array<string>,说明这是个string的数组

这样你就可以有更好的语法提示

比如我们可以封装一个简单的findIndex,类似lodash的一个函数,查找值的下标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/**
* @template T
* @param {T[]} arr
* @param {T} target
* @return {number}
*/
function findIndex(arr, target) {
let index = -1
for (let i = 0; i < arr.length; i++) {
let hasTarget = true
const targetKeys = Object.keys(target)
for (let j = 0; j < targetKeys.length; j++) {
// 如果没值 || 不相等
if (
typeof arr[i][targetKeys[j]] === 'undefined' ||
arr[i][targetKeys[j]] !== target[targetKeys[j]]
) {
hasTarget = false
break
}
}
// 如果 index 没值 && 有匹配的 target 则设置 index
if (index === -1 && hasTarget) {
index = i
break
}
}
return index
}

/**
* @type {{
* name?: string
* age?: number
* }[]}
*/
const test = [
{ name: '张三', age: 18 },
{ name: '李四', age: 20 },
{ name: '王五', age: 22 }
]

console.log(
findIndex(test, {
name: '王五'
}),

findIndex(test, {
age: 20
})
)

此时如果类型与传递的数组不相符,则会报错

其实这个例子举的不太好,因为那个函数本身只能传一个对象数组

js也确实不好举例子,这个泛型跟ts比还是有缺陷的,它没法单独传类型参数,只能通过形参传递

如果是ts你可以封装一个请求类,对请求参数进行约束:《请求接口类的封装》

其他字段

还有一些不太常用的(我个人不常用),可以参考官方文档

结语

OK,这次就说到这,这篇文章憋了20天

我太懒了,而且有些都是现研究的,之前研究这个泛型,一直想实现一个封装请求函数,自动提示返回参数,但实际比较难实现,因为就是上面说的JSDoc没法传递类型参数


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!