其实ESLint + TypeScript的组合还是挺香的,代码风格检查 + 类型检查,能省下不少时间。
但是还是存在一些问题。比如,有时候为了减小打包大小,我们可能会选择把一些不太关键的依赖放到CDN上,然后再通过<script>
来异步加载,这种脚本一般都会采用注入变量的方式来进行加载,这个时候就很麻烦。比如,我通过<script>
加载了d3,但是在使用的时候,就会报错:
ESLint: 'd3' is not defined.(no-undef)
TS2686: 'd3' refers to a UMD global, but the current file is a module. Consider adding an import instead.
解决起来也还比较简单。首先处理一下ts,给ts加一个类型声明文件来扩展全局变量。之前我曾经写过相关的文章,在这里重复一下。为了方便(并不代表应该写成any
,只是为了方便),在这里就暂时用一下any
:
// shims-global.d.ts
export {};
declare global {
interface Window {
d3: any;
}
const d3: any;
}
为什么第一行要写个export
?因为ts的模块机制,需要通过这个export
让编译器意识到这是一个模块。在之前的文章里也有相应的解释。
然后就是配置ESLint。网上目前主要是两种写法:
- 直接在rules里off掉这条规则。我觉得为了一个变量而关掉这项检查,不是一个很好的方案。
- 在
.eslintrc.js
里加这么一段:
module.exports = {
globals: {
'echarts': true
},
};
可以是可以,但是总觉得有点奇怪。为什么后面是个true
呢?
所以我去查了文档,文档上提供了好几种写法,在这里选两个常用的:
- 通过注释声明,只在当前文件生效。
最简单的写法如下:
/* global var1, var2 */
还可以对全局变量的读写权限进行更细粒度的控制。写法如下:
/* global var1:writable, var2:writable */
- 在
.eslintrc.js
进行配置,对整个项目都生效。
module.exports = {
globals: {
var1: 'writable',
var2: 'readonly'
}
};
在这种写法里,off是有特殊含义的,可以“屏蔽”原生的全局变量。比如,我不希望组里的其他人直接使用Promise(比如Promise.resolve
之类的方法,虽然我不知道什么情况下我会不想让别人用,但姑且认为我不想让其他人用),我就可以加上这么一个配置:
module.exports = {
globals: {
Promise: 'off'
}
};
这样,只要试图使用Promise,就会提示:
ESLint: 'Promise' is not defined.(no-undef)
需要注意的是,这里不能写成false
,否则规则不会生效,Promise
仍然是可用的。也由此可见,写成true
的那种写法并没有什么正确性,仅仅是因为有了一个值而已。