likes
comments
collection
share

[译]共同配置ESLint、Prettier和Typescript

作者站长头像
站长
· 阅读数 43

💡 原文地址

静态分析是一种在不运行代码的情况下审查代码的工具。这与动态分析形成对比:测试等执行您的代码并审查结果的工具。静态分析工具往往存在于速度和功能之间的谱系:

  1. 格式化工具(例如:Prettier):只快速的格式化你的代码风格,不关心逻辑
  2. Linters(例如:ESLint):以文件为单位,通过运行一组离散的规则来检查你的代码原始逻辑
  3. 类型检查(例如:TypeScript):一次生成对所有文件的理解,并验证代码行为是否符合意图

我最近在 React Miami 2023 上做了一个关于为 React 设置 ESLint 和 TypeScript 的演讲,其中包括我的建议。这篇博文涵盖了该演讲中的所有信息:描述如何开始使用JavaScript / TypeScript中的每种形式的静态分析,以及有效使用它们的一些快速提示。

抽象语法树(AST)

在我们深入研究这些工具之前,我想简要提及抽象语法树(AST)。

AST 是一个描述源代码内容的对象。静态分析工具通常会将源代码转换为AST,然后去理解代码。

例如,像 friend = friend || "me" 这样的代码会转换为下面的 AST:

{
    "expression": {
        "left": "friend",
        "operator": "=",
        "right": {
            "operator": "||",
            "type": "LogicalExpression",
            "left": "friend",
            "right": "\"me\""
        }
    },
    "type": "AssignmentExpression"
}

如果你想知道 TypeScript ASTs 是如何工作的,你可以在 ASTs and typescript-eslint 上找到相关内容,并在 typescript-eslint.io/play 上进行验证

AST 的概念有时候会出现在一些工具的文档中。虽然你无需了解AST即可使用静态分析工具,但他们通常是一个有用的概念。只要知道,当有人说AST时,他们谈论的是工具如何表示你的代码。

理论知识到此为止!接下来让我们深入研究这些工具。

格式化

格式化工具通过读取你的源代码,忽略格式,并建议你如果编写它。例如,给定一下格式奇怪的代码:

friend = friend 
		|| "me"

格式化工具可能会像这样去重写它:

 friend = friend|| "me"

请注意这不会更改代码的逻辑,它只会让代码更容易被人阅读。这太棒了,使用格式化工具,我们不需要手动格式化文件。

Prettier 是如今最常见的格式化工具。你可以通过将其作为依赖项来开始使用,然后在当前目录. 运行 --write 来自动格式化你的所有文件:

npm install prettier -D
npx prettier . --write

我鼓励你阅读 Prettier 文档Prettier 安装指南来获取更多的细节和配置。

编辑器格式化设置

我还鼓励你在 VS Code 工作区中启用 Prettier 拓展:

// .vscode/extensions.json
{
  "recommendations": ["esbenp.prettier-vscode"]
}

然后将其设置为默认格式化工具,在保存时自动格式化:

// .vscode/settings.json
{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true
}

这样,每次你保存文件或运行 VS Code 格式化文档命令时, Prettier 将会为你完全格式化文档。这意味你不需要手动的修复空格、换行符等。

Prettier 也有配置选项。但是我通常都是使用默认配置。只要我的格式是一致的,我就不会陷入纠结。我通常只会在配置中更改一个选项:

// .prettierrc.json
{
    "useTabs": true
}

如果你想更多的定制你的格式,你可能更喜欢使用 dprint 作为格式化工具,它比 Prettier 更具可配置型,尽管使用较少。

Linting

linter 是对源码运行一组检查的工具。现代的 linters,比如:ESLint、JavaScript标准的 linter,通常将它们设置为离散规则(规则独立运行,并且无法查看启用了哪些其他规则)。每个规则都可能报告它不喜欢的代码,并且每个消息可能包含可选的自动修复。

例如,如果你启用了 ESLint 的 logical-assignment-operators 规则,则会收到一条消息和建议的修复方法分,如下所示:

- friend = friend || "me"
+ friend ||= "me";
Assignment (=) can be replaced with operator assignment (||=).

要在本地开始使用 ESLint,你可以将其作为依赖项安装,运行其初始化程序来创建一个配置,并在当前目录. 运行 ESLint:

npm install eslint -D

npm init @eslint/config

npx eslint .

ESLint 配置

你的 ESLint 配置文件是所有 ESLint 插件(添加其他规则或其他 linting 行为的npm 包)和要启用或禁用的规则的配置选项的描述。每个规则都可以设置为以下三个值之一:

  • "off" :根本不会运行
  • "warn" :消息作为警告(黄色波浪线)显示,不会导致 ESLint 以非0状态码退出(即不会构建失败)
  • "error" :消息作为错误(红色波浪线)显示,并应导致 ESLint 以非0状态码退出(即构建失败)

手动配置每个规则是一项繁重的工作,许多项目启用了数百个规则!相反,ESLint 允许从预设配置中继承配置,我强烈建议至少从 ESLint 的 eslint:recommended 配置进行拓展,该配置包含 ESLint 团队发现对绝大多数 JavaScript 项目有用的规则

// .eslintrc.js
module.exports = {
    extends: "eslint:recommended",
};

精细规则配置

你始终可以禁用对你无用或者有太多错误的规则。没错,禁用 lint 规则是可以的!linter 跟其他工具一样,应该根据你的需求进行配置。

我对配置 ESLint 的一般建议是:

  1. 安装与你项目相关的所有插件

  2. 从每个插件的的推荐配置进行拓展

  3. 在 ESLint 配置中:

    1. 禁用你知道你不需要的任何规则,并解释原因
    2. 还要禁用你想要但是还没有时间启用的规则,并提交 issuce 来最终启用
// .eslintrc.js
module.exports = {
    extends: "eslint:recommended",
    rules: {
        // These rules are enabled by default, but we don't want
        "some-annoying-rule": "off", // (conflicts with XYZ preference)

        // Todo: these rules might be useful; we should investigate each
        "powerful-rule": "off", // (#123)
    },
};

为 React 配置 ESLint

由于链接的演讲是在 React 会议上给出的,它还展示了为 React 配置 ESLint。任何使用 JSX 和纯 JavaScript 的项目都需要将 parserOptions.ecmaFeatures.jsx 设置为 true ,以便 ESLint 的解析器知道允许 JSX。React 有两个常用的插件: eslint-plugin-react 用于所有 React, eslint-plugin-react-hooks 专门用于 hooks。 eslint-plugin-react 还要求配置 settings.react.version ,以便它知道要使用哪个特定于 React 版本的行为运行。

// .eslintrc.js
module.exports = {
  extends: [
    "eslint:recommended",
    "plugin:react/recommended",
    "plugin:react-hooks/recommended",
  ],
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
  },
  plugins: ["react", "react-hooks"],
  settings: {
    react: {
      version: "detect",
    },
  },
};

其他框架/库有自己的插件,包括 eslint-plugin-astro 、 eslint-plugin-solid 等。****

更多 Linting 标志

我通常建议在 ESLint 运行时再启用两个标志。

报告未使用的禁用指令

禁用指令是代码中的注释,用于禁用特定代码区域的部分或全部 ESLint 规则,例如,禁用单行日志的no-console

// eslint-disable-next-line no-console
console.log("Hello, world!");

默认情况下,ESLint 不会警告你,如果你把这些评论留在不需要它们的地方:

// eslint-disable-next-line no-console
myFancyLogger("Hello, world!");

--report-unused-disable-directives 导致 ESLint 将不必要的禁用指令视为与实际 lint 规则的消息相同。

// package.json
{
    "scripts": {
        "lint": "eslint . --report-unused-disable-directives"
    }
}

最大警告数

将值设置为 "warn" 的规则不会导致 ESLint 生成失败。根据我的经验,将规则保留为警告而不是错误会使它们随着时间的推移而累积,这会训练用户忽略它们。我建议仅对新启用的规则暂时使用 "warn" ,并在可能的情况下将所有规则配置为 "error" 。

--max-warnings 允许指定允许的最大警告数。如果 ESLint 收到的警告级别规则投诉多于该数字,它将切换到现有规则,并显示错误代码。

我建议将该数字保持在尽可能低的水平,最好是 0 :

// package.json
{
    "scripts": {
        "lint": "eslint . --max-warnings 0"
    }
}

编辑器 Linting 设置

我鼓励你在 VS Code 的工作区中启用 ESLint 拓展:

// .vscode/extensions.json
{
  "recommendations": ["dbaeumer.vscode-eslint"]
}

然后将其设置为默认格式化工具,在保存时自动运行:

// .vscode/settings.json
{
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }
}

这样,每次保存文件或运行 VS Code ESLint: 修复所有可自动修复的问题命令时,ESLint 都会为您 --fix 任何可修复的问题。如果您使用像 eslint-plugin-simple-import-sort 这样的插件,这将非常有用(我强烈推荐!)。

停止使用 ESLint 进行格式化

格式化工具不是 linter!linter 也不是格式化工具!这两种工具的内部工作原理不一样。

  • 格式化工具一次性重新格式化所有文件,这意味着比 linter 更快,但是不会查找逻辑问题
  • linter 运行一组离散的规则,这意味着比格式化工具慢,但是可以找到逻辑问题并提供修复建议

尽管 linter 可以具有针对格式量身定制的规则(例如 indent , max-len , semi ),这些规则变得非常复杂且难以维护,因为它们需要处理所有边缘情况。在 typescript-eslint 领域,我们已经完全放弃了 indent 规则。格式化规则是邪恶的,浪费时间进行维护,并且不是格式化代码的正确方法。请使用专用的格式化工具!

类型检查

今天,TypeScript 是 JavaScript 的标准类型检查器。人们喜欢将 TypeScript 描述为“JavaScript 的超集”(又名“JavaScript with types”)。但“TypeScript”这个词实际上指的是TypeScript团队提供的四件事:

  • 编程语言:一种语言的描述,其语法包括 JavaScript 中的所有语法和一些特定于类型的新内容
  • 类型检查器:一个用于读取文件并报告代码意图和执行方式不匹配的程序
  • 编译器:运行类型检查器的程序,以及将 TypeScript 源码转换为等效的 JavaScript 代码
  • 语言服务:在编辑器/IDE(如:VS Code)中运行编辑器和类型检查的程序

TypeScript 很有用,因为 JavaScript 中没有标准的内置方法来描述代码背后的意图。例如,这个 JavaScript 代码段声明了一个变量,但从不解释它允许包含什么类型的值:

let myValue; // what is this?!

TypeScript 类型注释语法将允许描述其意图(允许存储的值类型):

let myValue: number;

并且 TypeScript 类型检查器可以警告我们,如果我们为该变量分配了与我们声明的意图不符的内容:

myValue = "not a number";
// Error: Type 'string' is not assignable to type 'number'.

要在本地开始使用 TypeScript,您可以将其做为依赖项安装,运行其 init 命令以创建启动器配置,然后运行它:

npm install typescript -D

npx tsc --init

npx tsc

TypeScript 配置

tsc --init 将为您提供一个良好的启动配置。以下配置是我为大多数使用 React 或其他使用 JSX 的框架的项目推荐的最小配置:

  • "jsx" :告诉 TypeScript 应运行 jsx 语法
  • "module" :TypeScript 应该假设代码在哪个模块运行
  • "strict" :启用一套有用的类型检查规则,使 TypeScript 更加严格(因此它会捕获更多的问题)
  • "target" :指示 TypeScript 应假定哪些全局API 和环境语法功能可用

一些编译器宣讲在大部分项目中都会起作用:

  • "esModuleInterop" :告诉 TypeScript 在 CommonJS 和 ESM 模块之间导入时不要那么挑剔(因为默认情况下它非常迂腐)
  • "forceConsistentCasingInFileNames" :启用 TypeScript,让您知道是否使用错误的大小写输入
  • "skipLibCheck" : 防止 TypeScript 花费时间进行类型检查 node_modules

aka.ms/tsconfig 介绍了每个可用的编译器选项。我还在学习打字稿>第13章:配置选项中更深入地解释了其中的许多。

请注意,编译器选项通常由框架启动器(如 create-next-app )为您设置。只要他们设置 strict: true ,你应该没问题。****

TypeScript 编辑器配置

我通常建议在VS Code 工作区中使用如下设置:

// .vscode/settings.json
{
    "eslint.rules.customizations": [{ "rule": "*", "severity": "warn" }],
    "typescript.tsdk": "node_modules/typescript/lib"
}

"eslint.rules.customizations" 告诉 VS Code 将所有 ESLint 规则投诉可视化为黄色(警告)波浪线,而不是与其配置的严重性匹配的波浪线颜色。我发现这很有用,因为 TypeScript 投诉通常显示为红色(错误)波浪线。让两个工具以相同的颜色显示投诉可能会令人困惑。以红色显示 TypeScript 投诉,以黄色显示 ESLint 投诉有助于人们了解哪个是哪个。

"typescript.tsdk" 告诉 VS Code 它应该使用项目已安装的 TypeScript 包作为 IDE 工具,而不是计算机的全局 VS Code / TypeScript 安装。这很好,因为项目安装的 TypeScript 版本可能与 VS Code 不同。您不希望在终端上运行 tsc 与从 VS Code 的语言服务运行 TypeScript 的结果可能不同。

TypeScript 不是 Linter

不要将 linting 和类型检查混淆。两者是不一样的。

  • 传统的 linter 运行一组离散可配置的规则,一次只能看到一个文件,这意味着它比类型检查器更快、更可配置。
  • 类型检查器可以完全理解所有文件,这意味着它比传统的 linter 慢,但在推断方面更强大。

您可以将区别视为:

  • 类型检查器让您知道代码何时明显没有意义(例如,在应该只接收字符串的地方提供数值)
  • Linters 会让您知道代码何时有意义,但可能是错误的(例如,调用标记为 @deprecated 的函数)

我之所以说传统的 linter,是因为稍后我们将看到如何启用使用 TypeScript API 的强大 lint 规则。 ****

Linting TypeScript 代码

默认情况下,ESLint 只理解 JavaScript 语法,而不能理解 TypeScript 中包含的新语法。它的核心规则不适用于特定于 TypeScript 的逻辑或最佳实践。这就是为什么 Typescript-eslint 为 ESLint 用户提供了两个软件包:

  • @typescript-eslint/eslint-plugin :提供针对 TypeScript 代码量身定制的 lint 规则和预设配置
  • @typescript-eslint/parser : 告诉 ESLint 如何读取 TypeScript 语法

Prettier也在内部使用 typescript-eslint,这就是它支持 TypeScript 语法的方式。

typescript-eslint.io 包括一个用于检查 TypeScript 代码的入门指南。我可以建议使用的最直接的 linter 配置利用这两个包来扩展 ESLint 推荐的规则以及 [plugin:@typescript-eslint/recommended](<https://typescript-eslint.io/linting/configs#recommended>) ,这是 TypeScript 的等效入门配置:

// eslintrc.js
module.exports = {
    extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
    parser: "@typescript-eslint/parser",
    plugins: ["@typescript-eslint"],
};

例如, @typescript-eslint/prefer-as-const 规则可以通知开发人员使用 as const 而不是在类型断言中重新键入文本值:

- let me = { name: "ReactMiami" as "ReactMiami" };
+ let me = { name: "ReactMiami" };

类型感知规则

传统的 lint 规则一次只能看到一个文件。typescript-eslint 提供的 API 允许规则进入 TypeScript 的类型检查器 - 从而对更强大的 lint 规则进行分类。这些“类型感知”lint 规则未在 plugin:@typescript-eslint/recommended 中启用,因为它们比传统的 lint 规则慢得多,因为它们以类型检查的速度运行(需要在整个项目上运行)。

typescript-eslint的类型信息代码检查指南展示了启用这些规则所需的步骤。最小要求如下:

module.exports = {
    extends: [
        "eslint:recommended",
        "plugin:@typescript-eslint/recommended",
+        "plugin:@typescript-eslint/recommended-requiring-type-checking",
    ],
    plugins: ["@typescript-eslint"],
    parser: "@typescript-eslint/parser",
+    parserOptions: {
+        project: true,
+    },
};
  • plugin:@typescript-eslint/recommended-requiring-type-checking 是我们推荐的配置,它另外启用类型感知规则
  • typescript-eslint 需要 parserOptions.project 才能知道哪个 TSConfig 包含用于生成类型信息的编译器选项; true 指示使用最接近每个源文件的文件

例如, @typescript-eslint/await-thenable 报告在非 thenable 语句(如 Promise )上使用的任何 await 。

据我所知,使用 typescript-eslint 的类型感知 lint 规则是当今JavaScript / TypeScript项目可以获得的最强大的lint规则。我强烈建议使用它们!****

将一切整合到一起

让我们回顾一下这些工具是如何交互的:

  • 格式化工具(如 Prettier)可快速格式化代码,无需担心代码逻辑
  • 诸如 ESLint 之类的 Linter 在代码逻辑上运行一组离散规则
  • 类型检查器(如 TypeScript)可以了解您的项目,并在违反声明的意图时出错
  • typescript-eslint 允许 ESLint 解析 TypeScript 代码,并将 TypeScript 类型检查 API 公开给 ESLint 规则

Linting TypeScript in 2023 :是一个演示存储库,显示了所有这些工具的配置,以及使用三个类型检查的打字稿-eslint 规则在 React 应用程序中捕获三个错误的示例。

另请参阅单独的常见问题解答文章,了解有关静态分析的各种问题。****

转载自:https://juejin.cn/post/7238027797313290277
评论
请登录