2 min read

jsdoc为Nodejs server项目引入类型

ts并不是唯一解

Table of Contents

背景

在对接外部api时,拿到的响应obj,往往结构极其复杂,各种嵌套,加上字段命名不规范,无法确定用途。在开发过程中,js数量超过200行后,没有类型提示,很快就忘了变量是干什么的了。这时候灾难性的后果就会显现:运行时出现类型错误,反复回忆变量含义,等等。

那么,引入类型就十分必要了。不过新的问题是,如何为一个现存项目引入类型呢?在这个场景中,项目是一个Nodejs server,所有代码都是js,用ts改写,成本太大,而且需要额外的编译步骤才能上线。还有除了个别复杂的api需要类型,大部分api的内部并不涉及太过复杂的逻辑。

jsdoc

ts官方文档有一个专题介绍在js中引入类型的,分三步走:

  1. 在js文件顶部添加// @ts-check (这一步不仅是为了作为jsdoc的前置条件,还能发现拼写错误、undefined、重复定义等问题)
  2. 添加jsdoc注释
  3. 用ts重写js文件

@ts-check开启后,违背类型检查的代码才会被IDE报错。如果一些错误处你认为无需标出(比如引用了一个没有类型提示的外部库),你可以使用@ts-ignore来忽略错误。

jsdoc是注释形式添加类型的,这就带来了很大的灵活性。

📦 最常用的 JSDoc 语法

1. 给函数加注释

/**
 * 加法函数
 * @param {number} a 第一个数字
 * @param {number} b 第二个数字
 * @returns {number} 返回相加结果
 */
function add(a, b) {
  return a + b;
}

2. 给变量加类型

/** @type {string} */
let name = "Lee";

/** @type {number[]} */
let scores = [90, 85, 100];

常用类型:

类型写法
数字number
字符串string
布尔值boolean
数组string[] 或 Array<string>
对象Object 或 {foo: string, bar: number}
函数function 或更详细签名见下
任意类型* 或 any
可选参数@param {string} [name]
默认值参数@param {string} [name="张三"]
返回类型@returns {string}

3. 自定义对象类型(接口)

/**
 * @typedef {Object} User
 * @property {string} name 姓名
 * @property {number} age 年龄
 */

/**
 * 打印用户信息
 * @param {User} user
 */
function printUser(user) {
  console.log(`${user.name}, ${user.age}`);
}

4. 给函数签名加类型

/**
 * @param {(a: number, b: number) =&gt; number} fn - 接收一个函数参数
 */
function calc(fn) {
  return fn(1, 2);
}

把jsdoc放在单独的文件里

独立文件有两种方法,一种是配合tsconfig放在dts,一种是放在js文件。我认为js文件更适合,因为引入ts会让项目结构变得很奇怪。创建一个types.js文件,比如:

/**
 * @typedef {Object} User
 * @property {string} name 姓名
 * @property {number} age 年龄
 */

然后在index.js中引入:

import './types.js' // 运行时不会导入
/**
 * @param {User} user
 */

const user = {
  name: '张三',
  age: 18
}

总结

jsdoc是属于ts生态系统内的类型工具,借助vscode等IDE,以低成本享受类型便利。对于复杂的代码,可以按需引入,而不影响整体结构。唯一缺点可能是语法比typescript啰嗦一点。


Jason Lee
Hi, I'm Jason Lee

I hope I can still be curious about the world when I turn 60 years old.

Enjoy!

Contact me:

Email | GitHub


Content licenced under CC BY-NC-ND 4.0