ESLint 批量抑制:技术债治理的正确打开方式
引子:一个技术 Leader 的困境
作为技术 Leader,你可能遇到过这样的场景:
团队维护着一个两年前的 React 项目,20 万行代码,技术债堆积如山。你想推动代码质量提升,在团队会议上提议:"我们开启 @typescript-eslint/no-explicit-any 规则吧,减少 any 的滥用。"
然后你在本地试运行了一下:
$ eslint .
✖ 1,247 problems (1,247 errors, 0 warnings)
1,247 个错误。
你的第一反应可能是:"算了,还是别开了。" 团队成员也松了一口气——毕竟谁也不想在 JIRA 里看到一个"修复 1,247 个 Lint 错误"的任务。
但问题是,如果现在不开启规则,新代码还会继续使用 any,技术债只会越滚越大。这就是典型的"存量问题拖累增量改进"的困境。
今天要介绍的 ESLint 批量抑制(Bulk Suppressions) 功能,就是为了解决这个问题而生的。
核心思路:既往不咎,严控增量
批量抑制的核心理念可以用八个字概括:既往不咎,严控增量。
工作机制
当你启用批量抑制后,ESLint 会做三件事:
- 记录现状:将当前所有违规记录到
eslint-suppressions.json文件中 - 暂时放行:对于已记录的旧代码违规,ESLint 暂时忽略,CI/CD 正常通过
- 严格卡控:对于新增的代码,规则立即生效,任何新违规都会报错
看一个实际的抑制文件示例:
{
"suppressions": [
{
"ruleId": "@typescript-eslint/no-explicit-any",
"file": "src/components/UserProfile.tsx",
"count": 12
},
{
"ruleId": "@typescript-eslint/no-explicit-any",
"file": "src/utils/request.ts",
"count": 8
}
]
}
这个文件告诉 ESLint:"UserProfile.tsx 文件里有 12 个 any,这是历史遗留问题,暂时放过。但如果出现第 13 个,立即报错。"
监控机制
批量抑制不是"一抑了之",而是有严格的监控:
// src/components/UserProfile.tsx
// 已记录 12 个 any,当前 12 个 → 通过
// 如果开发者新增了一个 any:
function handleData(data: any) { // 这是第 13 个!
// ...
}
// ESLint 会立即报告该文件的所有违规:
// ✖ 13 problems in src/components/UserProfile.tsx
一旦违规数超标,ESLint 会暴露该文件的所有问题,倒逼开发者要么修复新问题,要么顺手把旧问题也一起解决。
实战:在 React + TypeScript 项目中落地
场景设定
假设你负责一个电商项目,技术栈是 React + TypeScript,团队 8 人,代码库现状:
- 150+ 个组件文件
- TypeScript 配置较宽松(
strict: false) - 大量使用
any、非空断言、隐式类型转换 - 团队对"突然冒出的几百个 Lint 错误"非常抵触
你的目标是:在不影响现有开发节奏的前提下,逐步提升代码质量。
第一步:评估现状
先看看如果直接开启严格规则会怎样:
// eslint.config.js
export default [
{
files: ["**/*.{ts,tsx}"],
rules: {
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-non-null-assertion": "error",
"@typescript-eslint/strict-boolean-expressions": "error"
}
}
];
运行检查:
$ eslint .
src/components/ProductList.tsx
12:15 error Unexpected any. Specify a different type @typescript-eslint/no-explicit-any
23:8 error Forbidden non-null assertion @typescript-eslint/no-non-null-assertion
...
src/utils/formatPrice.ts
5:22 error Unexpected any. Specify a different type @typescript-eslint/no-explicit-any
...
✖ 847 problems (847 errors, 0 warnings)
847 个错误。如果强行推进,结果可想而知:
- 团队成员抱怨:"又要加班修 Bug 了"
- CI/CD 构建失败,阻塞所有人的开发
- 最后可能不得不回滚配置
第二步:使用批量抑制
冷静下来,换个思路——用批量抑制:
# 1. 开启规则并生成抑制文件
$ eslint . --suppress-all --fix
# 自动修复了 142 个问题
# 剩余 705 个问题记录到 eslint-suppressions.json
✔ Suppressions written to eslint-suppressions.json
这个命令做了两件事:
- 自动修复:能自动修复的问题(比如添加类型注解)直接修复
- 记录存量:无法自动修复的问题记录到抑制文件
现在再运行 eslint .:
$ eslint .
✔ No problems found
完美通过!关键是,新代码必须符合规则。
第三步:验证增量卡控
让我们验证一下,新代码是否真的会被拦截。
某个开发者在新功能中写了这样的代码:
// src/components/NewFeature.tsx (新文件)
import React from 'react';
interface Props {
data: any; // x 新代码使用 any
}
export default function NewFeature({ data }: Props) {
return <div>{data.name}</div>;
}
运行检查:
$ eslint src/components/NewFeature.tsx
src/components/NewFeature.tsx
4:9 error Unexpected any. Specify a different type @typescript-eslint/no-explicit-any
✖ 1 problem (1 error, 0 warnings)
立即报错!因为这是新文件,不在抑制列表中。
开发者必须修复才能提交:
// 修复后
interface ProductData {
name: string;
price: number;
}
interface Props {
data: ProductData; // 使用明确的类型
}
第四步:建立日常工作流
1. 定期清理已修复的抑制
当团队修复了一些旧代码后,使用 --prune-suppressions 清理:
$ eslint . --prune-suppressions
✔ Removed 23 suppressions that are no longer needed
这个命令会:
- 检查每个抑制项是否还存在对应的违规
- 如果违规已修复,从抑制文件中移除该记录
2. Code Review 关注点
在代码评审时,增加一个检查项:
## Code Review Checklist
- [ ] 代码逻辑正确
- [ ] 测试覆盖充分
- [ ] **技术债趋势**:
- [ ] 没有新增 eslint-suppressions.json 中的抑制项
- [ ] 如果修改了旧文件,是否顺手修复了部分 Lint 问题
进阶技巧
技巧 1: 按模块分批抑制
如果你想先对核心模块严格要求,可以这样操作:
# 先对 utils 和 hooks 目录开启严格模式
$ eslint src/utils src/hooks --suppress-all --fix
# 其他目录暂时不检查
技巧 2: 结合 Git Hooks
推荐使用 lint-staged 来精确控制只检查暂存区的文件,比手写脚本更稳健:
-
安装依赖:
npm install --save-dev lint-staged husky -
配置
package.json:{ "lint-staged": { "*.{ts,tsx}": [ "eslint" ] } } -
在
.husky/pre-commit中调用:#!/bin/sh npx lint-staged
这样,每次提交时,ESLint 只会检查你修改的文件。如果有新增的违规(且未被抑制),提交将被拦截。
技巧 3: 制定“童子军规则”
在团队中推行童子军规则(Boy Scout Rule):
"离开时,让代码比你来时更干净一点。"
具体做法:
- 如果你修改了某个旧文件,顺手修复 1-2 个 Lint 问题
- 在 Code Review 时,给予"技术债修复"额外的认可
总结:技术债治理的三个原则
通过 ESLint 批量抑制功能,我们学到的不仅是一个工具的使用,更是一种技术债治理的方法论:
原则 1: 不要让存量问题阻碍增量改进
传统思维:"要么全修,要么不修"。 批量抑制思维:"存量暂时冻结,增量严格卡控"。
原则 2: 渐进式改进优于一次性重构
一次性重构的风险:
- 周期长,风险高
- 影响业务交付
- 团队抵触情绪大
渐进式改进的优势:
- 每次改进可见、可控
- 不影响正常迭代
- 团队负担小
原则 3: 用工具和流程保障,而非靠自觉
不要指望团队成员"自觉地"提升代码质量。应该:
- 工具拦截:ESLint 自动检查新代码
- CI 监控:自动检测技术债趋势
- 流程保障:Code Review 检查清单
参考资料
如果这篇文章对你有帮助,欢迎点赞收藏!也欢迎在评论区分享你在技术债治理方面的经验和困惑。