上次写文章已经是一年前了, 来拔下草...
维护一个有几年历史的 JavaScript 项目是非常辛苦的(如果碰巧这个项目之前的开发不怎么喜欢写文档和注释, 就更难了)。
假设你需要给里面一部分功能打些补丁, 那么你常常就会面对如下场景:WTF这个对象有啥属性? 通过一堆console.log
和断点调试
终于搞定了, 发誓再也不碰这段代码了。
几个月以后又有需求需要在这里打些补丁, 然后就会再次出现:WTF这个对象有啥属性? ...
也想过引入 TypeScript 来解决以上问题, 它能提供 IDE 自动补全还有最重要的类型安全。但是面对 1000+ 个 js 文件, 算了算了。
这篇文章提供了一种渐进式引入 TypeScript 的方式, 可供大家参考。
秘诀就是JSDoc, 其实很多 JavaScript 代码编辑器都支持 JSDoc, 比如我常用的 Visual Studio Code 和 Webstorm 。
下面用一个案例来介绍具体怎么使用 JSDoc 。
假设我们有一个 meeting.js
文件, 描述了如何将成员渲染到页面上。里面大致代码如下:
// meeting.js// 成员let members = [{id: '001', nickName: 'wang', role = 'speaker'}];// 视频流let streams = {'001': MagicStreamObject()};function renderMeetingMembers(members, streamSources) {// 发言人let speakers = members.filter(x => x.role === 'speaker');// 其他人let others = members.filter(x => x.role !== 'speaker');// 将成员与流关联起来speakers.forEach(speaker => {let stream = streams[speaker.id];if (stream) {speaker.stream = stream;}});// 非常复杂的渲染逻辑renderMembers(speakers, others);}renderMeetingMembers(members, streams);
要给上面这个文件加上「类型注释」应该怎么做呢?
因为上面两个代码编辑器都默认支持 TS 文件, 那么我们可以方便的在项目里新建任意 TS 文件。里面大致代码如下
// meeting.d.tsexport interface MagicStream {play: () => void;stop: () => void;};export type Member {id: string;nickName: string;role: 'speaker' | 'role';stream?: MagicStream;};
至于什么时候用 type, 什么时候用 interface 随便你...
第一步, 引入类型。使用 @typedef 和 import
// meeting.js/** @typedef {import('./meeting.d.ts').MagicStream} MagicStream *//** @typedef {import('./meeting.d.ts').Member} Member */
第二步, 用 @type 给普通变量加上类型
/** @type {Member[]} */let members = [{ id: '001', nickName: 'wang', role = 'speaker' }];/** @type {{ [userId: string]: MagicStream }} */let streams = {'001': MagicStreamObject()};
第三步, 给函数参数加上注释
/*** @param {Member[]} members - 参会成员* @param {{ [userId: string]: MagicStream }} streamSources - 流**/function renderMeetingMembers(members, streamSources) {// blabla}
做完这几步以后基本上编辑器就能自动补全代码了!!!
随着 d.ts
文件积累越来越多,是时候开始真正引入 TSC 来编译整个项目了。
去网上随便抄个教程吧,注意关键点是 tsconfig.json
里面有个重要选项:allowJS
- 混写 JavaScript 和 TypeScript 。
没啥特别的难度, 一点点修复警告⚠️。实在不行 any 大法好!!!