如何在Typescript中使用ESLint

6,224 阅读5分钟

ESLint是一个JavaScript linter,您可以使用它来检测TypeScript或JavaScript代码。在本文中,我们将逐步介绍如何在您的项目中设置校验。

介绍

在编写干净的代码时,格式化是几个要关注的问题之一。我们还应该关注很多其他事情,但是格式化是我们可以立即设置并为我们的项目建立标准的那些事情之一。

ESLint and TSLint

由名称就可想象两者作用,但是官方已经不维护TSLint了。因此,2020年以后,我们将继续寻求ESLint满足我们所有的TypeScript(和JavaScript)校验需求!

安装和配置

运行以下代码在你的TypeScript项目中配置ESlint。

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

创建一个.eslintrc.js文件

touch .eslintrc.js

在里面进行如下配置

module.exports = {
  parser: '@typescript-eslint/parser', // an eslint parser allow eslint to lint typescript source code
  parserOptions: {
    sourceType: 'module', // 设置为 "script" (默认) 或 "module"(如果你的代码是 ECMAScript 模块)。 
    // https://eslint.bootcss.com/docs/user-guide/configuring
  }
 }

parserOptions参数详解

ESLint允许你指定你想要支持的javascript语言选项。默认情况下,ESLint支持 ECMAScript 5 语法。你可以覆盖该设置,以启动对 ECMAScript 其他版本和 JSX 的支持。

请注意,支持 JSX 语法并不等同于支持 React。React 对 ESLint 无法识别的JSX语法应用特定的语义。如果你正在使用 React 并且想要 React 语义支持,我们建议你使用 eslint-plugin-react。

同样的,支持 ES6 语法意味着同时支持新的 ES6 全局变量或类型(比如全局变量:importexport,以及Set等新数据类型)。

如果不配置,会报以下错误:

  1:1  error  Parsing error: The keyword 'import' is reserved
  1:1  error  Parsing error: The keyword 'export' is reserved
  • 对于 ES6 语法,使用 { "parserOptions": { "ecmaVersion": 6 } }
  • 对于新的 ES6 全局变量,使用 { "env":{ "es6": true } }

{ "env": { "es6": true } } 自动启用es6语法,但 { "parserOptions": { "ecmaVersion": 6 } } 不自动启用es6全局变量。

解析器选项可以在 .eslintrc.* 文件使用parserOptions属性设置。可用的选项有:

  • ecmaVersion - 默认设置为 3,5(默认), 你可以使用 6、7、8、9 或 10 来指定你想要使用的 ECMAScript 版本。你也可以用使用年份命名的版本号指定为 2015(同 6),2016(同 7),或 2017(同 8)或 2018(同 9)或 2019 (same as 10)
  • sourceType - 设置为 "script" (默认) 或 "module"(如果你的代码是 ECMAScript 模块)。
  • ecmaFeatures - 这是个对象,表示你想使用的额外的语言特性:
  • globalReturn - 允许在全局作用域下使用 return 语句
  • impliedStrict - 启用全局 strict mode (如果 ecmaVersion 是 5 或更高)
  • jsx - 启用 JSX
  • experimentalObjectRestSpread - 启用实验性的 object rest/spread properties 支持。(重要:这是一个实验性的功能,在未来可能会有明显改变。 建议你写的规则 不要 依赖该功能,除非当它发生改变时你愿意承担维护成本。)

添加ESLint规则

eslint的一个规则有三个模式:offwarnerror

  • “off”的值是0(完全关闭该规则)
  • “warn”的值是1(开启规则,错误只提醒,不会不通过)
  • “error”的值是2(开启规则,命中则不通过) 添加规则,就在配置文件中,增加属性rules如下:
const DOMGlobals = ['window', 'document']
const NodeGlobals = ['module', 'require']

module.exports = {
  parser: '@typescript-eslint/parser', // an eslint parser allow eslint to lint typescript source code
  parserOptions: {
    sourceType: 'module', // 设置为 "script" (默认) 或 "module"(如果你的代码是 ECMAScript 模块)。 
    // https://eslint.bootcss.com/docs/user-guide/configuring
  },
  rules: {
    'no-unused-vars': [
      'error',
      // we are only using this rule to check for unused arguments since TS
      // catches unused variables but not args.
      { varsIgnorePattern: '.*', args: 'none' },
    ],
    // most of the codebase are expected to be env agnostic
    // 禁用特定的全局变量,在不明确环境的情况下,禁用特定环境的的全局变量
    'no-restricted-globals': ['error', ...DOMGlobals, ...NodeGlobals],
    // since we target ES2015 for baseline support, we need to forbid object
    // rest spread usage (both assign and destructure)
    'no-restricted-syntax': [
      'error',
      'ObjectExpression > SpreadElement',
      'ObjectPattern > RestElement',
    ],
  },
  overrides: [
    // tests, no restrictions (runs in Node / jest with jsdom)
    {
      files: ['**/__tests__/**', 'test-dts/**'],
      rules: {
        'no-restricted-globals': 'off',
        'no-restricted-syntax': 'off',
      },
    },
    // shared, may be used in any env
    {
      files: ['packages/shared/**'],
      rules: {
        'no-restricted-globals': 'off',
      },
    },
    // Packages targeting DOM
    {
      files: ['packages/{vue,runtime-dom}/**'],
      rules: {
        'no-restricted-globals': ['error', ...NodeGlobals],
      },
    },
    // Packages targeting Node
    {
      files: ['packages/{compiler-sfc,compiler-ssr,server-renderer}/**'],
      rules: {
        'no-restricted-globals': ['error', ...DOMGlobals],
        'no-restricted-syntax': 'off',
      },
    },
    // Private package, browser only + no syntax restrictions
    {
      files: ['packages/template-explorer/**', 'packages/sfc-playground/**'],
      rules: {
        'no-restricted-globals': ['error', ...NodeGlobals],
        'no-restricted-syntax': 'off',
      },
    },
  ],
}

添加插件

ESLint 还允许您向配置中添加一次性功能。这些被称为插件。这是一个有趣的。这被称为no-loops

查看其他 awesome-eslint 插件和配置的列表。

no-loops 是一个插件,它使您能够指定for, for-in, while, do-while, for-of循环是非法的,只能使用 map forEach 之类的函数来代替。

安装如下:

npm install --save-dev eslint-plugin-no-loops

配置如下:

{
    "plugins": ["no-loops"],
    "rules": {
        "no-loops/no-loops": 2
    }
}

扩展一个不同的基础ESLint配置

通常可以通过规则文档在他们的网站上找到 eslint 基本规则。如果你想换一个基础配置,比如shopify

您可以将多个基本配置添加到您的项目中,方法是将它们包含在数组中,尽管您最终可能会看到相同的 linting 规则两次或更多次。

npm install eslint-plugin-shopify --save-dev

配置如下:

{
  "root": true,
  "parser": "@typescript-eslint/parser",
  "extends": [
    "plugin:shopify/esnext"
  ]
}

使用 ESLint 修复 linted 代码

您可能已经注意到,在ESLint错误消息的末尾,说"2个错误和0个警告可能可以使用 --fix 选项修复”。可以运行 ESLint 并修复它能够同时修复的问题。

package.json文件的scripts里新增如下命令:

"lint-and-fix": "eslint . --ext .ts --fix"

还可以配合,统一格式化项目代码的prettier,效果会更好。

指定特定扩展名的文件ESLint检测

ESLint 检查指定代码块的文件扩展名,如果 --ext [CLI option] 不包含文件扩展名,则忽略这些扩展名。如果您想要删除除 *.js 之外的已命名代码块,请确保指定 --ext 选项。

目前,告诉 ESLint 哪个文件扩展名要检测的唯一方法是使用 --ext 命令行选项指定一个逗号分隔的扩展名列表。注意,该标记只在与目录一起使用时有效,如果使用文件名glob 模式,它将会被忽略。

如下命令行的意思是:检查packages/*/src文件夹下的所有ts文件。

"lint": "eslint --ext .ts packages/*/src/**",