震惊!JavaScript 竟然可以类型推断!

作者 | 朱士奇

杏仁前端开发工程师,代码洁癖症早期,关注前端技术。

作为弱类型的写起来爽,维护起来更

—— 鲁迅·沃梅硕果

近几年,前端技术的发展可以用来形容,因此也被大规模的运用在项目中,由此也产生了代码的维护问题,所谓。其实不仅仅是代码重构,在日常开发中也能感受到弱类型语言的不足所带来的不便之处。举个例子,现在有个函数, 作用是将用户列表显示在界面上

functionrenderUserList(el,userList){

lethtml='';for(constuserofuserList){html+=`

姓名:${user.age}

年龄:${user.age}

`}el.innerHTML=html;

}

我敢打赌,大家在写这种类型函数的时候,都是在盲写,因为我们不知道传入的和到底是什么类型。更不知道下面有哪些方法,写的时候都如此费劲,跟别谈维护了。其实我们可以通过一些简单的操作,让这个函数写起来更轻松,就像下面一样:

那么,到底是怎么实现的呢?接下来就要介绍本文的主角JSDoc和VSCode

JSDoc是一个根据 JavaScript 文件中注释信息,生成 JavaScript 应用程序或库、模块的 API 文档 的工具。你可以使用他记录如:命名空间,类,方法,方法参数等。

通俗的讲,JSDoc 是 JavaScript 注释规范的一种,VSCode 利用 JSDoc 规范的特点,配合 typescript 实现了“类型提示”,所以在 VSCode 中基本上是开箱即用的,而对于非内置对象,比如 jQuery 的 $,lodash 的 _ 等,则需要单独下载对应的声明文件。不过实际开发中,在 window 和 mac 上,还是有些差别的,mac 版的 VSCode 会去检查代码,然后自动下载对应的声明文件存放在 ~/Library/Caches/typescript/ (猜测是自动下载的),而 windows 则需要开发者手动通过 npm 去安装需要的声明文件,文末也会提到如何使用声明文件。另外在中也可以使用 JSDoc,webstorm 也支持通过 JSDoc 实现类型提示, sublime 貌似还不支持。在 VSCode 中会自动根据 JSDoc 的标注对变量、方法、方法参数等进行类型推断,通过 TypeScript 来进行智能提示,因此从编写注释开始学习 TypeScript 也是一个不错的选择,下面就来一一列举 JSDoc 在代码中的用法。变量用标注变量的类型基础类型

/**

* @type

*/

letn;

/** @type */

letflag;

/** @type */

letstr;

联合类型

如果一个变量可能是多种类型,则可以使用联合类型

/**

* @type

*/

letx;

自定义类型

我们经常用到自定义类型,也就是中的对象,对于简单的对象,可以用下面的写法

/**

* @type {}

*/

letuser;

对于键值对比较多的复杂对象,可以使用来定义复杂类型,用或者来定义对象的属性。

/**

* @typedef goods

* @property name

* @prop code

* @prop thumbnail 用 = 表示该属性是可能存在,也可能不存在

* @prop [introduction] 也可以给属性名加上 [] 表示这是一个可选属性

* @prop label

*//**

* @type

*/letphone;

数组

可以使用或者表示数组

/**

* @type

*/

letnumList;

/**

* @type

*/

letstrList;

对于已经定义的类型或者已经声明的变量,也是可以直接使用,下面分别声明一个数组和数组

/**

* @type

*/

letuserList;

/**

* @type

*/

letgoodsList;

如果不确定数组的每一项具体类型,可以使用或者交叉类型

/**

* @type

*/

letarr1;

/**

* @type {*[]}

*/

letarr2;

/**

* @type {(user | goods)[]}

*/

letarr3

泛型

/*** @template T* @param p1* @return*/

functiongen(p1){

returnp1

}

函数

用表示函数的名称用表示函数的参数用或表示函数的返回值一般函数的写法大致分为两种:声明式函数和函数表达式。函数表达式

/**

* @type

*/

vargetSum=(n1,n2)=>n1+n2;

声明式函数

/**

* @name fn

* @param str

* @param flag

* @returns {*[]}

*/

functionfn(str,flag){return[];

}

通过上面的注释写法,便可以在函数内部正确的识别出两个参数的类型,并且可以知道该函数返回值类型为数组。对于函数参数的类型,写法和上面的变量写法一致,区别是将换成了,函数的返回值也是同样的道理。对象的方法对函数的注释同样适用于对象的方法

varo={

/**

* @param msg

* @returns

*/say(msg){console.log(msg);}

}

内置类型和其它类型

上面的例子只是简单的用到了一些常见的类型,然而在实际开发中,我们用到的不止这些,比如开始文章开头的例子中,有用到了对象,那该怎么编写注释呢?其实已经为我们提供了很多的类型了,比如对象对应的类型是, 事件对象对应的类型是,同时对象还可以更细化,比如、等等。同时,我们在开发中也会用到第三方的类库或框架,通常情况下,这些类库都会有一份以结尾的声明文件,该声明文件中包含了所用到类型的所有提示,以最为经典的为例,如果在时在环境下,在通过 npm 安装 jQuery 后,需要再单独安装对应的声明文件,这样 VSCode 就可以正确的识别符号,也可以在 JSDoc 中使用,等这都类型了,就像下面这样

/**

* @type

*/

var$btn=$('button');

/**

* @param userId

* @returns

*/

functiongetUser(userId){return$.get(`/user/${userId}`);

}

大部分情况下,通过 npm 发布的包,都会包含其对应的声明文件,如果没有的话,可以通过这个地址TypeSearch来搜索一下并安装 ,如果感兴趣可以到这个仓库DefinitelyTyped看看。当然你也可以提供一些仓库内目前还没有声明文件,别人会非常感谢你的!当然并不是所有的项目都用到了 npm ,仍有很多项目在使用这种方式从 cdn 来引入文件,这种情况下用不到 webpack ,也用不到 npm ,那这个时候就要从上面所提到的仓库地址DefinitelyTyped来下载对应的声明文件了,然后通过这种形式来引入声明文件,就像下面这样

///

个人建议:即使是通过 cdn 方式来引入文件,也可以通过 npm 来安装,这样和在每个文件中通过引入声明文件相比,还是方便很多的。总结以上便是关于利用 JSDoc 实现 JavaScript 的类型提示。当然还有一些更深入的用法,比如全局模板文件,命名空间等,但是这些和 TypeScript 关系更大一些。当有一天你发现 JSDoc 已经不能满足你的时候,便是向着 TypeScript 大举进攻的时候了。

全文完

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180815G1FTG000?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券