TypeScript 代码检查

  • 时间:
  • 浏览:141
  • 来源:网络编程网

目前 TypeScript 的代码检查主要有两个方案:使用 TSLint 或使用 ESLint + typescript-eslint-parser

什么是代码检查

代码检查主要是用来发现代码错误、统一代码风格。

在 JavaScript 项目中,我们一般使用 ESLint 来进行代码检查。它通过插件化的特性极大的丰富了适用范围,搭配 typescript-eslint-parser 之后,甚至可以用来检查 TypeScript 代码。

TSLint 与 ESLint 类似,不过除了能检查常规的 js 代码风格之外,TSLint 还能够通过 TypeScript 的语法解析,利用类型系统做一些 ESLint 做不到的检查。

为什么需要代码检查

有人会觉得,JavaScript 非常灵活,所以需要代码检查。而 TypeScript 已经能够在编译阶段检查出很多问题了,为什么还需要代码检查呢?

因为 TypeScript 关注的重心是类型的匹配,而不是代码风格。当团队的人员越来越多时,同样的逻辑不同的人写出来可能会有很大的区别:

  • 缩进应该是四个空格还是两个空格?
  • 是否应该禁用 var
  • 接口名是否应该以 I 开头?
  • 是否应该强制使用 === 而不是 ==

这些问题 TypeScript 不会关注,但是却影响到多人协作开发时的效率、代码的可理解性以及可维护性。

下面来看一个具体的例子:

let myName = 'Tom';

console.log(`My name is ${myNane}`);
console.log(`My name is ${myName.toStrng()}`);
console.log(`My name is ${myName}`)

// tsc 报错信息:
//
// index.ts(3,27): error TS2552: Cannot find name 'myNane'. Did you mean 'myName'?
// index.ts(4,34): error TS2551: Property 'toStrng' does not exist on type 'string'. Did you mean 'toString'?
//
//
//
// eslint 报错信息:
//
// /path/to/index.ts
//   3:27  error  'myNane' is not defined         no-undef
//   5:38  error  Missing semicolon               semi
//
// ✖ 2 problems (2 errors, 0 warnings)
//   1 errors, 0 warnings potentially fixable with the `--fix` option.
//
//
//
// tslint 报错信息:
//
// ERROR: /path/to/index.ts[5, 36]: Missing semicolon

存在的问题tsc 是否报错eslint 是否报错tslint 是否报错
myName 被勿写成了 myNane✅✅❌
toString 被勿写成了 toStrng✅️❌❌
少了一个分号❌✅✅

上例中,由于 eslinttslint 均无法识别 myName 存在哪些方法,所以对于拼写错误的 toString 没有检查出来。

而代码风格的错误不影响编译,故少了一个分号的错误 tsc 没有检查出来。

对于未定义的变量 myNanetsc 可以检测出来。由于用到 tslint 的地方肯定会接入 tsc 编译,所以 tslint 就没必要检测这个错误了。eslint 需要能够独立于某个编译环境运行,所以能检测出此类错误,而对于 TypeScript 代码,这其实是一种冗余的检测了。

事实上,不止 tsceslint 之间有冗余的检测,tsctslint 之间也有一些冗余的检测,但是大部分都是因为早期的 tsc 还没能做到检测此类错误。

举个例子,TSLint 中的 typeof-compare 要求 typeof 表达式比较的对象必须是 'undefined', 'object', 'boolean', 'number', 'string', 'function''symbol' 之一。而 TypeScript 2.2 之后,编译器就已经自带了这个功能。

下图表示了 tsc, eslinttslint 能覆盖的检查:

上图中,tsc, eslinttslint 之间互相都有重叠的部分,也有各自独立的部分。

虽然发现代码错误比统一的代码风格更重要,但是当一个项目越来越庞大,开发人员也越来越多的时候,代码风格的约束还是必不可少的。

应该使用哪种代码检查工具

TSLint 与 ESLint 作为检查 TypeScript 代码的工具,各自有各自的优点:

TSLint 的优点:

  1. 专为 TypeScript 服务,bug 比 ESLint 少
  2. 不受限于 ESLint 使用的语法树 ESTree
  3. 能直接通过 tsconfig.json 中的配置编译整个项目,使得在一个文件中的类型定义能够联动到其他文件中的代码检查

ESLint 的优点:

  1. 基础规则比 TSLint 多很多(249 : 151)
  2. 社区繁荣,插件众多(50+ : 9)

下面来看一些具体的例子:

let foo: string = 1 + '1';

// tslint 报错信息:
//
// ERROR: /path/to/index.ts[1, 19]: Operands of '+' operation must either be both strings or both numbers, consider using template literals

以上代码在 TSLint 中会报错,原因是加号两边必须同为数字或同为字符串(需要开启 restrict-plus-operands 规则)。

ESLint 无法知道加号两边的类型,所以对这种规则无能为力。

function foo(a, b, c, d, e, f, g, h) {
    doSomething();
}

// eslint 报错信息:
//
// /path/to/index.ts
//   1:1  error  Function 'foo' has too many parameters (8). Maximum allowed is 7  max-params
//
// ✖ 1 problem (1 error, 0 warnings)

ESLint 可以检测出来以上代码的函数参数超过了 7 个(需要开启 max-params 规则)。

但是 TSLint 没有此项检查,虽然也可以实现,但是需要自己手动写一条规则。

那么到底该使用哪种代码检测工具呢?经过一些实践,我建议可以按照以下流程决定:

在 TypeScript 中使用 ESLint

安装 ESLint

ESLint 可以安装在当前项目中或全局环境下,因为代码检查是项目的重要组成部分,所以我们一般会将它安装在当前项目中。可以运行下面的脚本来安装:

npm install eslint --save-dev

由于 ESLint 默认使用 Espree 进行语法解析,无法识别 TypeScript 的一些语法,故我们需要安装 typescript-eslint-parser,替代掉默认的解析器,别忘了同时安装 typescript

npm install typescript typescript-eslint-parser --save-dev

由于 typescript-eslint-parser 对一部分 ESLint 规则支持性不好,故我们需要安装 eslint-plugin-typescript,弥补一些支持性不好的规则。

npm install eslint-plugin-typescript --save-dev

创建配置文件

ESLint 需要一个配置文件来决定对哪些规则进行检查,配置文件的名称一般是 .eslintrc.js.eslintrc.json

当运行 ESLint 的时候检查一个文件的时候,它会首先尝试读取该文件的目录下的配置文件,然后再一级一级往上查找,将所找到的配置合并起来,作为当前被检查文件的配置。

我们在项目的根目录下创建一个 .eslintrc.js,内容如下:

module.exports = {
    parser: 'typescript-eslint-parser',
    plugins: [
        'typescript'
    ],
    rules: {
        // @fixable 必须使用 === 或 !==,禁止使用 == 或 !=,与 null 比较时除外
        'eqeqeq': [
            'error',
            'always',
            {
                null: 'ignore'
            }
        ],
        // 类和接口的命名必须遵守帕斯卡命名法,比如 PersianCat
        'typescript/class-name-casing': 'error'
    }
}

以上配置中,我们指定了两个规则,其中 eqeqeq 是 ESLint 原生的规则(它要求必须使用 ===!==,禁止使用 ==!=,与 null 比较时除外),typescript/class-name-casingeslint-plugin-typescript 为 ESLint 增加的规则(它要求类和接口的命名必须遵守帕斯卡命名法,比如 PersianCat)。

规则的取值一般是一个数组(上例中的 eqeqeq),其中第一项是 offwarnerror 中的一个,表示关闭、警告和报错。后面的项都是该规则的其他配置。

如果没有其他配置的话,则可以将规则的取值简写为数组中的第一项(上例中的 typescirpt/class-name-casing)。

关闭、警告和报错的含义如下:

  • 关闭:禁用此规则
  • 警告:代码检查时输出错误信息,但是不会影响到 exit code
  • 报错:发现错误时,不仅会输出错误信息,而且 exit code 将被设为 1(一般 exit code 不为 0 则表示执行出现错误)

检查一个 ts 文件

创建了配置文件之后,我们来创建一个 ts 文件看看是否能用 ESLint 去检查它了。

创建一个新文件 index.ts,将以下内容复制进去:

interface person {
    name: string;
    age: number;
}

let tom: person = {
    name: 'Tom',
    age: 25
};

if (tom.age == 25) {
    console.log(tom.name + 'is 25 years old.');
}

然后执行以下命令:

./node_modules/.bin/eslint index.ts

则会得到如下报错信息:

/path/to/index.ts
   1:11  error  Interface 'person' must be PascalCased  typescript/class-name-casing
  11:13  error  Expected '===' and instead saw '=='     eqeqeq

✖ 2 problems (2 errors, 0 warnings)

上面的结果显示,刚刚配置的两个规则都生效了:接口 person 必须写成帕斯卡命名规范,== 必须写成 ===

需要注意的是,我们使用的是 ./node_modules/.bin/eslint,而不是全局的 eslint 脚本,这是因为代码检查是项目的重要组成部分,所以我们一般会将它安装在当前项目中。

可是每次执行这么长一段脚本颇有不便,我们可以通过在 package.json 中添加一个 script 来创建一个 npm script 来简化这个步骤:

{
    "scripts": {
        "eslint": "eslint index.ts"
    }
}

这时只需执行 npm run eslint 即可。

检查整个项目的 ts 文件

我们的项目源文件一般是放在 src 目录下,所以需要将 package.json 中的 eslint 脚本改为对一个目录进行检查。由于 eslint 默认不会检查 .ts 后缀的文件,所以需要加上参数 --ext .ts

{
    "scripts": {
        "eslint": "eslint src --ext .ts"
    }
}

此时执行 npm run eslint 即会检查 src 目录下的所有 .ts 后缀的文件。

在 VSCode 中集成 ESLint 检查

在编辑器中集成 ESLint 检查,可以在开发过程中就发现错误,极大的增加了开发效率。

要在 VSCode 中集成 ESLint 检查,我们需要先安装 ESLint 插件,点击「扩展」按钮,搜索 ESLint,然后安装即可。

VSCode 中的 ESLint 插件默认是不会检查 .ts 后缀的,需要在「文件 => 首选项 => 设置」中,添加以下配置:

{
    "eslint.validate": [
        "javascript",
        "javascriptreact",
        "typescript"
    ]
}

这时再打开一个 .ts 文件,将鼠标移到红色提示处,即可看到这样的报错信息了:

使用 AlloyTeam 的 ESLint 配置

ESLint 原生的规则和 eslint-plugin-typescript 的规则太多了,而且原生的规则有一些在 TypeScript 中支持的不好,需要禁用掉。

这里我推荐使用 AlloyTeam ESLint 规则中的 TypeScript 版本,它已经为我们提供了一套完善的配置规则。

安装:

npm install --save-dev eslint typescript typescript-eslint-parser eslint-plugin-typescript eslint-config-alloy

在你的项目根目录下创建 .eslintrc.js,并将以下内容复制到文件中:

module.exports = {
    extends: [
        'eslint-config-alloy/typescript',
    ],
    globals: {
        // 这里填入你的项目需要的全局变量
        // 这里值为 false 表示这个全局变量不允许被重新赋值,比如:
        //
        // jQuery: false,
        // $: false
    },
    rules: {
        // 这里填入你的项目需要的个性化配置,比如:
        //
        // // @fixable 一个缩进必须用两个空格替代
        // 'indent': [
        //     'error',
        //     2,
        //     {
        //         SwitchCase: 1,
        //         flatTernaryExpressions: true
        //     }
        // ]
    }
};

使用 ESLint 检查 tsx 文件

如果需要同时支持对 tsx 文件的检查,则需要对以上步骤做一些调整:

安装 eslint-plugin-react

npm install --save-dev eslint-plugin-react

package.json 中的 scripts.eslint 添加 .tsx 后缀

{
    "scripts": {
        "eslint": "eslint src --ext .ts,.tsx"
    }
}

VSCode 的配置中新增 typescriptreact 检查

{
    "eslint.validate": [
        "javascript",
        "javascriptreact",
        "typescript",
        "typescriptreact"
    ]
}

使用 AlloyTeam ESLint 规则中的 TypeScript React 版本

AlloyTeam ESLint 规则中的 TypeScript React 版本

在 TypeScirpt 中使用 TSLint

TSLint 的使用比较简单,参考官网的步骤安装到本地即可:

npm install --save-dev tslint

创建配置文件 tslint.json

{
    "rules": {
        // 必须使用 === 或 !==,禁止使用 == 或 !=,与 null 比较时除外
        "triple-equals": [
            true,
            "allow-null-check"
        ]
    },
    "linterOptions": {
        "exclude": [
            "**/node_modules/**"
        ]
    }
}

package.json 添加 tslint 脚本

{
    "scripts": {
        "tslint": "tslint --project . src/**/*.ts src/**/*.tsx",
    }
}

其中 --project . 会要求 tslint 使用当前目录的 tsconfig.json 配置来获取类型信息,很多规则需要类型信息才能生效。

此时执行 npm run tslint 即可检查整个项目。

在 VSCode 中集成 TSLint 检查

在 VSCode 中安装 tslint 插件即可,安装好之后,默认是开启的状态。

使用 AlloyTeam 的 TSLint 配置

AlloyTeam 为 TSLint 也打造了一套配置 tslint-config-alloy

npm install --save-dev tslint-config-alloy

安装之后修改 tsconfig.json 即可

{
    "extends": "tslint-config-alloy",
    "rules": {
        // 这里填入你的项目需要的个性化配置,比如:
        //
        // 一个缩进必须用两个空格替代
        // "indent": [
        //     true,
        //     "spaces",
        //     2
        // ]
    },
    "linterOptions": {
        "exclude": [
            "**/node_modules/**"
        ]
    }
}

使用 TSLint 检查 tsx 文件

TSLint 默认支持对 tsx 文件的检查,不需要做额外配置。

Troubleshootings

Cannot find module 'typescript-eslint-parser'

你运行的是全局的 eslint,需要改为运行 ./node_modules/.bin/eslint

cannot read property type of null

需要关闭 eslint-plugin-react 中的规则 react/jsx-indent

如果仍然报错,多半是因为某些规则需要被关闭,可以使用「二分排错法」检查是哪个规则造成了错误。也欢迎给 eslint-config-alloy 提 issue。

VSCode 没有显示出 ESLint 的报错

  1. 检查「文件 => 首选项 => 设置」中有没有配置正确
  2. 检查必要的 npm 包有没有安装
  3. 检查 .eslintrc.js 有没有配置
  4. 检查文件是不是在 .eslintignore

如果以上步骤都不奏效,则可以在「文件 => 首选项 => 设置」中配置 "eslint.trace.server": "messages",按 Ctrl+Shift+U 打开输出面板,然后选择 ESLint 输出,查看具体错误。

为什么 ESLint 无法检查出使用了未定义的变量(no-undef 规则为什么被关闭了)?

因为 typescript-eslint-parser 无法支持 no-undef 规则。它针对正确的接口定义会报错。

所以我们一般会关闭 no-undef 规则。

为什么有些定义了的变量(比如使用 enum 定义的变量)未使用,ESLint 却没有报错?

因为无法支持这种变量定义的检查。建议在 tsconfig.json 中添加以下配置,使 tsc 编译过程能够检查出定义了未使用的变量:

{
    "compilerOptions": {
        "noUnusedLocals": true,
        "noUnusedParameters": true
    }
}

启用了 noUnusedParameters 之后,只使用了第二个参数,但是又必须传入第一个参数,这就会报错了

第一个参数以下划线开头即可,参考 https://github.com/Microsoft/TypeScript/issues/9458

为什么有的错误 TSLint 可以检查出来,vscode 里的 TSLint 却检查不出来?

因为 TSLint 依赖 tsconfig.json 获得了类型信息,而 vscode 里的 TSLint 暂不支持获取类型信息,所以 no-unused-variable 就失效了。

不仅 no-unused-variables 失效了,TSLint rules 里面所有标有 Requires Type Info 的规则都失效了。


猜你喜欢

天天飞车航哥破解版 v1.0.18 安卓版 下载

天天飞车航哥破解版是腾讯热门游戏天天飞车的破解版本,这款天天飞车破解版本是航哥破解的,目前没有异常,没封号风险,注意的

2018-09-20

JQuery里的原型prototype分析

在JavaScript中,每个函数对象都有一个默认的属性prototype,称为函数对象的原型成员,这个属性指向一个对象,称为函数的原型对象,当我们每定义了一个函数的时候,Ja

2018-09-20

支付宝香港版下载 支付宝HK 2018 V1.4.1 安卓版 下载

脚本之家 服务器常用软件 手机版 投稿中心&

2018-09-19

iPhone5/5s联通4G手机助手 v1.18 官方安装版 解锁4G无需越狱 下载

脚本之家 服务器常用软件 手机版 投稿中心&

2018-09-19

微信6.0 安卓 微信 V6.5.6 for Android 官方中文免费 正式版 下载

微信,超过3亿人使用,能够通过手机网络给好友发送语音、文字消息、表情、图片和视频,还可以分享照片到朋友圈。通过摇一摇、

2018-09-19