从"代码能跑就行"到"代码能跑且优雅",中间隔着一个 ESLint。
一句话回答
ESLint 是一个 JavaScript/TypeScript 代码静态分析工具------它不运行你的代码,而是读你的代码,找出里面的语法错误、坏味道和不一致的风格,然后告诉你哪里该改、怎么改。
为什么需要 ESLint?
1. 拦截低级错误,趁早不赶晚
js
// 你觉得这段代码有什么问题?
if (isAdmin = true) {
deleteUserAccount();
}
= 写成了 ==?不,是赋值写进了 if 条件里。这段代码能跑,不会报语法错误,但它会在你不注意的时候把用户账号删了。ESLint 的 no-cond-assign 规则会在你写下的那一刻就标红警告。
类似的还有:
- 变量声明了但没使用(
no-unused-vars) console.log忘了删(no-console)- 在
return后面写了不可达代码(no-unreachable) ==和===混用(eqeqeq)
这些 bug 在运行时往往很难排查,但在静态分析阶段花 0.1 秒就能发现。
2. 统一团队风格,消灭无意义的 Code Review 争论
"花括号应该写同一行还是换行?" "缩进用 tab 还是空格?" "分号加不加?"
这些问题不该出现在 Code Review 里。它们没有对错,但一旦团队不统一,阅读代码时就会产生认知负担。ESLint 把这些风格决策固化成规则,代码提交前自动检查,不符合就报错。
js
// ESLint 让团队的代码长成同一个样子
const foo = () => {
if (condition) {
doSomething();
}
};
3. 强制执行最佳实践
JavaScript 有很多"能跑但不好"的写法。ESLint 内置了大量最佳实践规则:
| 规则 | 防止什么 |
|---|---|
no-var |
鼓励用 let/const 替代 var,避免变量提升陷阱 |
prefer-const |
声明后不修改的变量必须用 const |
no-eval |
禁止 eval(),防止注入攻击 |
no-implicit-globals |
禁止意外创建全局变量 |
prefer-arrow-callback |
鼓励箭头函数,减少 this 绑定问题 |
no-duplicate-case |
防止 switch 里写重复的 case |
4. 与编辑器深度集成,实时反馈
VS Code、WebStorm 等编辑器都支持 ESLint 插件。你写代码的同时,编辑器就能:
- 在有问题的代码下画红色波浪线
- 显示具体问题和修复建议
- 一键自动修复 (
--fix)
这种"写错即纠"的体验,比等 CI 跑完才发现问题高效得多。
ESLint 的工作原理
ESLint 的核心流程可以概括为三步:
解析 → 遍历 → 报告
- 解析 :ESLint 把你的源代码解析成 AST(抽象语法树)。JavaScript 用 Espree 解析器,TypeScript 需要配合
@typescript-eslint/parser。 - 遍历:ESLint 遍历 AST 的每个节点,每碰到一个节点就检查有没有匹配的规则。
- 报告 :匹配到规则后,根据规则配置(
off/warn/error)输出对应级别的诊断信息。
插件 提供规则,配置 决定哪些规则开启、开到什么级别。这就是 ESLint "插件 + 配置" 的设计哲学。
快速上手
安装
bash
npm install -D eslint
初始化配置
bash
npx eslint --init
ESLint 会问你几个问题(项目类型、框架、是否用 TypeScript 等),然后生成 .eslintrc.js:
js
// .eslintrc.js --- 旧版配置格式(eslintrc)
module.exports = {
env: {
browser: true,
es2021: true,
node: true,
},
extends: 'eslint:recommended',
parserOptions: {
ecmaVersion: 2021,
sourceType: 'module',
},
rules: {
'no-unused-vars': 'warn',
'no-console': 'warn',
'eqeqeq': 'error',
'prefer-const': 'error',
},
};
新版配置格式(Flat Config)
ESLint 9+ 默认使用扁平化配置 eslint.config.js:
js
// eslint.config.js
import js from '@eslint/js';
export default [
js.configs.recommended,
{
rules: {
'no-unused-vars': 'warn',
'no-console': 'warn',
'eqeqeq': 'error',
},
},
];
扁平配置用数组代替继承链,更直观、更容易理解每条规则从哪来。
运行
bash
# 检查所有文件
npx eslint .
# 检查并自动修复
npx eslint . --fix
# 只检查特定文件
npx eslint src/**/*.js
配合 npm scripts
json
{
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint . --fix"
}
}
常用规则速查
错误检测类
js
rules: {
'no-unused-vars': 'error', // 声明但未使用的变量
'no-undef': 'error', // 使用未定义的变量
'no-unreachable': 'error', // return 后的不可达代码
'no-cond-assign': 'error', // 条件语句中出现赋值
'no-debugger': 'error', // debugger 语句
}
风格规范类
js
rules: {
'indent': ['error', 2], // 统一缩进 2 空格
'quotes': ['error', 'single'], // 统一单引号
'semi': ['error', 'always'], // 强制分号
'no-trailing-spaces': 'error', // 禁止行尾空格
'eol-last': 'error', // 文件末尾空行
}
最佳实践类
js
rules: {
'eqeqeq': 'error', // 必须用 === 而非 ==
'no-eval': 'error', // 禁止 eval
'no-var': 'error', // 禁止 var
'prefer-const': 'error', // 优先用 const
'no-multiple-empty-lines': ['error', { max: 2 }],
}
建议:风格类规则交给 Prettier 处理,ESLint 专注代码质量和最佳实践,两者各司其职。后面会展开说。
与 Prettier 的关系
很多人搞不清 ESLint 和 Prettier 的区别,简单说:
| ESLint | Prettier | |
|---|---|---|
| 关注什么 | 代码质量 + 代码风格 | 纯代码格式化 |
| 典型问题 | 未使用的变量、== vs ===、不可达代码 |
缩进、引号、换行、行宽 |
| 能修复逻辑吗 | 能发现问题,部分能自动修复 | 不能,只改格式不改逻辑 |
| 能配规则吗 | 能,几百条 | 几乎不能,只有几个选项 |
最佳实践:两者一起用。
- ESLint 负责"代码对不对"
- Prettier 负责"代码好不好看"
- 用
eslint-config-prettier关闭 ESLint 中与 Prettier 冲突的格式化规则
bash
npm install -D prettier eslint-config-prettier
js
// .eslintrc.js
module.exports = {
extends: [
'eslint:recommended',
'prettier', // 放最后,关闭冲突的格式规则
],
};
TypeScript 项目怎么配?
TypeScript 项目需要额外的解析器和插件:
bash
npm install -D @typescript-eslint/parser @typescript-eslint/eslint-plugin
js
// eslint.config.js
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
export default tseslint.config(
js.configs.recommended,
...tseslint.configs.recommended,
{
rules: {
'@typescript-eslint/no-unused-vars': 'warn',
'@typescript-eslint/no-explicit-any': 'warn',
},
},
);
@typescript-eslint 能检查类型层面的错误,比如:
- 显式使用
any类型(no-explicit-any) - 非空断言
!滥用(no-non-null-assertion) - 不安全的类型断言(
no-unsafe-assertion)
配合 Git Hook 自动化
最理想的状态是:代码提交前自动检查,不合格的代码根本进不了仓库。
用 lint-staged + husky
bash
npm install -D husky lint-staged
npx husky init
json
// package.json
{
"scripts": {
"prepare": "husky"
},
"lint-staged": {
"*.{js,ts,jsx,tsx}": "eslint --fix"
}
}
bash
echo "npx lint-staged" > .husky/pre-commit
这样每次 git commit 时,ESLint 会自动检查暂存区的文件,有问题就阻止提交。只有新增/修改的文件会被检查,不会全量扫描,速度很快。
常见配置预设
与其从零配置,不如站在巨人肩膀上。社区提供了很多成熟的配置预设:
| 预设 | 特点 |
|---|---|
eslint:recommended |
ESLint 官方推荐,覆盖最常见的错误检测 |
eslint-config-airbnb |
Airbnb 的严格风格规范,曾经是社区标准 |
eslint-config-standard |
标准风格,无分号、无冗余配置 |
eslint-config-next |
Next.js 官方配置,包含 React + a11y 规则 |
eslint-config-react-app |
CRA 内置配置 |
eslint-config-prettier |
关闭与 Prettier 冲突的规则 |
js
// 组合使用
export default [
js.configs.recommended,
...reactHooks.configs.recommended,
...reactRefresh.configs.vite,
prettierConfig, // 放最后
];
总结
ESLint 解决的核心问题:让错误尽早暴露、让风格保持一致、让最佳实践成为习惯。
| 不用 ESLint | 用 ESLint |
|---|---|
| Bug 到运行时才暴露 | 写代码时就发现 |
| Code Review 在争论分号 | Code Review 聚焦逻辑 |
| 每个人代码风格不同 | 团队代码如同出自一人 |
| 新人不了解最佳实践 | 规则本身就是文档和教学 |
如果你还没在项目里用 ESLint,现在就装一个吧:
bash
npm install -D eslint
npx eslint --init
你的代码库会感谢你。