8

背景


越来越多的前端项目开始使用typescript这门静态检查语言了,它包括很多很棒的功能点,在这里就不细述,根据静态语法检查和.d.ts生成的代码提示两大特性,我们就可以来制定并且检查代码规范,现在我们来详细说一下。

代码规范


代码规范大家应该是从开始写第一行代码开始别人就开始和你说,要遵循xx代码规范。公司不同,规范的内容、形式、检查方式也不同,但最终是要验收你的规范。
如果是通过leader code review方式来检查代码,那效率也就太低了,最好的方式就是在GIT提交之前做检查。你的代码不合规范,提交都提交不上去,这样就能从入口上保证代码的规范性。
我们再说看下前端的代码规范情况,前端的代码主要就是js的代码,因为js的灵活性以及随意性,让工具来检查代码的规范成为不可能,这也是我一直头疼的事,因为规范这种东西,说再多遍,不来点强制手段,组内之前也是不可能达成一致的。直到Typescript的出现,解决了这个问题。

Typescript检查的原理


Typescriptjavascript的超集,所以ts在运行之前,得先编译成js,那么这个编译的过程,ts的编译引擎就得知道,文件里包括哪些方法,方法包含哪些参数,各参数的定义是什么,类型是什么,总之,所有源信息必须都知道,才能准确无误的把ts翻译成js。这些东西也正是我们需要的,通过这些信息,我们就可以对比规范和源信息,来确认是否是符合我们制定规范的代码。

初步实现


顺着这个思路,我查了查typescript的官方文档,果然找到了一个,叫做Compiler API,最后的那个例子,是和我们的需求相关的,把代码拿下来,也是可以跑通的,所以呢,下一步,就是基于这个例子进行扩展,来满足我们自己的需求。
实现的过程,也是挺痛苦的,因为没有文档,也没有说明,幸亏在vscode可以点进行看声明文件,好消息是可以看到方法的定义,坏消息就是所有的方法的声明、类型,都没有注释,部分需要自己来猜,哈哈,有总比没有强,照猫画虎,总算实现了基本功能。

clipboard.png

官方的.d.ts大致就长这样

开发之中,有一个问题比较难解决,就是在目前可观测的API中,只能constructor可以取到返回值类型,其他方法API根本不提供,最后借助stackoverflow上提问,解决了这个问题,有兴趣的同学可以参考下:how to use typescript Compiler API to get normal function info, eg: returnType/parameters?

检查你的代码


现在已经可以检查你的代码了,我们上面也说了,最好的检查时机是开发人员提交的时候,这时会检查所有的代码,只有所有的代码都符合规范,才会提交成功,这是我们最理想的情况。
按照这个思路,我们可以查到,Git有很多钩子,pre-commitcommit-msgpost-commit等等,我们使用pre-commit:提交前检查,会执行.git/hooks/pre-commit下的脚本文件,但是这个文件分布在组内所有人的笔记本中,并且不能增加版本控制。带着这样的疑问,我们找到了pre-commit这个神器,它的实现原理也是修改上面的文件,不过它从node层屏蔽了实现细节,我们只要在package.json里面增加一个script就可以实现我们要的功能。

配置大概是这样:

...
"pre-commit": ["commit"],
"script":{
    ...
    "commit": "ts-node verify.ts"
    ...
}
...

这样在git里面commit(不管使用命令行还是SourceTree这样图形界面)的时候就会执行ts-node verify.ts,检查要是失败了,就会把错误信息打印到控制台上,并且提交会失败,直到所有的已定规则都验证通过,才会提交成功。

检查失败,大致就是这样的:

clipboard.png

还有一个更大的作用


我们已经通过上一步,能够检查我们的规范了,知道代码的所有信息,比如生成.d.ts文件!对一个对外提供的工具库来讲,如果没有一套完整的.d.ts文件进行代码提示的话,那就显的太不专业了。如果要生成一个完整的提示文件,就必须要求你的类、方法、参数、返回值都要有完整的注释,这些就应该在你的代码规范中。

我们来看一下,比较好的例子:

clipboard.png

知道了所有的信息,生成这个文件其实就是字符串的拼接,没什么技术含量,不过生成的格式还得注意一下。

兼容所有情况的.d.ts写法


一般我们使用一个库文件的时候,都会有三种用法:

import Util from 'xxx/Util'
import {DateTime, Fiel} from 'xxx/Util'
import * as Util from 'xxx/Util'

在使用的时候,这三种形式所需要的.d.ts文件的格式也是不一样的,所以作为对外提供服务的库文件来说,所有的使用方式,我们都应该兼容。经过多次尝试,这样格式的.d.ts文件是兼容所有用法:

export class DateTime {
    static dateFormat(....)
}

declare const exDe: {
    DateTime: typeof DateTime
}

export default exDe

源码


Demo的源码以及使用效果,用力点我
Demo中用到的代码检查工具,用力点我

使用效果

  • 检查失败的情况

clipboard.png

  • 检查成功的情况

clipboard.png


会说话的鱼
2.9k 声望219 粉丝