过去我们使用 ESLint,主要是为了统一代码风格、防止低级错误、减少 code review 里的争论。
但 AI 进入开发流程以后,ESLint 的角色应该变一变。
以前的问题是:
人写代码不稳定,所以需要规则约束人。
现在的问题更像是:
AI 写代码很快,但可能机械满足规则,却不理解业务语义。
所以 AI 时代的 ESLint,不应该只是更严格,而应该是更高信号、更少噪音、更贴近真实 bug。
1. ESLint 的本质:确定性护栏
ESLint 擅长的事情是确定性判断。
比如:
js
const obj = {
name: 'A',
name: 'B',
};
这个一定有问题,因为前一个 name 会被后一个覆盖。
规则:
perl
no-dupe-keys
这类规则非常适合 ESLint。
再比如:
vue
<a-radio v-model="record.electStatus == 1 ? true : false" />
这个也一定有问题,因为 v-model 必须绑定到可赋值表达式。
规则:
bash
vue/valid-v-model
这也是 ESLint 应该管的。
ESLint 最适合管这种问题:
语法上明确错
运行时大概率错
团队里无论谁看都应该修
2. AI 时代,最怕的是低信号规则
所谓低信号规则,就是它报错了,但不一定代表代码真的有风险。
比如:
js
for (const item of list) {
if (!item.valid) break;
}
Airbnb Base 可能因为 no-restricted-syntax 禁止 for...of。
你可以改成:
js
list.some((item) => {
if (!item.valid) {
return true;
}
return false;
});
这能过 lint,但它一定更好吗?不一定。
尤其是 AI 写代码时,它很容易为了过规则做机械改写:
rust
for...of -> some
for...in -> Object.keys().forEach
三元表达式 -> if else
长行 -> 拆数组
有些改写是好的,有些只是形式变化。
如果 ESLint 里低信号规则太多,AI 会把大量精力花在"满足风格"上,而不是"理解业务"。
3. AI 会放大 ESLint 规则的好坏
人类修 lint 时,可能会停下来想:
kotlin
这里能不能改?
会不会影响 break?
会不会影响 await?
会不会影响 this?
AI 如果没有明确上下文,很可能直接替换。
例如:
js
for (const item of list) {
await save(item);
}
如果 AI 机械改成:
js
list.forEach(async (item) => {
await save(item);
});
这就是 bug。
因为 forEach 不会等待内部 async。原来是顺序保存,改后变成并发触发,而且外层不会等它完成。
这说明:低质量 ESLint 规则会诱导 AI 做错误的"合规改写"。
所以 AI 时代,我们更需要重新治理 ESLint 规则。
4. 更好的原则:保留防 bug,减少风格洁癖
我建议把规则分三类。
第一类:必须保留。
这些是真正防 bug 的规则:
perl
no-dupe-keys
no-undef
no-unused-vars
no-unreachable
no-empty
no-unused-expressions
no-mixed-operators
no-unsafe-optional-chaining
consistent-return
vue/valid-v-model
import/no-cycle
它们报错时,大概率代表真实风险。
例如:
css
disabled={a && b || c && d}
虽然 JS 知道优先级,但人容易读错。加括号更安全:
scss
disabled={(a && b) || (c && d)}
规则:
perl
no-mixed-operators
这类规则应该保留。
第二类:视项目情况保留。
这些规则有价值,但不能教条:
perl
no-restricted-syntax
prefer-destructuring
max-len
no-nested-ternary
no-param-reassign
no-plusplus
比如 no-restricted-syntax 禁 for...in 是有道理的,因为 for...in 会遍历原型链。
但禁所有 for...of 就不一定合理。对于需要 break、continue、await 的循环,for...of 反而更清楚。
第三类:交给 Prettier。
格式类规则不应该由 ESLint 反复争:
缩进
空格
换行
引号
分号
对象换行
行宽
这类东西应该交给 Prettier:
代码格式自动化,不占用人和 AI 的判断力。
5. ESLint 和 Prettier 的分工
一个更现代的配置思想是:
Prettier 管格式
ESLint 管风险
TypeScript 管类型
AI 管语义审查
不要让 ESLint 同时承担所有事情。
Prettier 负责:
这段代码长什么样
ESLint 负责:
这段代码有没有明显风险
TypeScript 负责:
这个值的类型对不对
测试负责:
这个行为有没有变
AI 负责:
这个改动在业务链路里是否合理
这几个工具应该协作,而不是互相抢工作。
6. Parser 也要升级
ESLint 能不能看懂代码,取决于 parser。
老项目常见:
vbnet
parser: 'babel-eslint'
但 babel-eslint 已经是旧包了。现代项目一般用:
vbnet
parser: '@babel/eslint-parser'
TypeScript 项目用:
vbnet
parser: '@typescript-eslint/parser'
Vue 项目还需要:
vue-eslint-parser
Parser 升级的价值是:
更懂现代语法
更少误报
更少工具崩溃
能结合类型信息做更强检查
这次我们遇到的 ESLint 崩溃,就是旧 ESLint / 旧 parser / 新语法组合下的典型问题。
代码里一个可选链:
scss
parseFloat(...)?.toFixed(n)
放在模板字符串里,触发了 ESLint 7 的规则内部错误。
这类问题,单靠改业务代码不是根治。长期还是要升级工具链。
7. AI 时代的理想 ESLint 配置
一个更适合 AI 协作的 ESLint 配置,不应该追求"最严格",而应该追求"最高信号"。
例如:
js
module.exports = {
extends: [
'eslint:recommended',
'plugin:vue/recommended',
'prettier',
],
rules: {
'no-dupe-keys': 'error',
'no-undef': 'error',
'no-unreachable': 'error',
'no-empty': 'error',
'no-unused-expressions': 'error',
'no-mixed-operators': 'error',
'no-unsafe-optional-chaining': 'error',
'consistent-return': 'warn',
'vue/valid-v-model': 'error',
'prefer-destructuring': 'off',
'no-plusplus': 'off',
'no-restricted-syntax': [
'error',
{
selector: 'ForInStatement',
message: 'Use Object.keys/Object.entries unless inherited enumerable properties are explicitly required.',
},
{
selector: 'WithStatement',
message: 'with makes scope ambiguous.',
},
],
},
};
这里的重点是:不要一刀切禁 ForOfStatement。
因为:
js
for (const item of list) {
if (item.invalid) break;
}
在很多情况下比 some() 更清楚。
8. 规则报错也应该更"解释型"
传统 ESLint 报错是:
perl
no-restricted-syntax
这对新同事和 AI 都不友好。
更好的规则 message 应该解释原因:
css
Avoid for...in because it iterates inherited enumerable properties.
Use Object.keys/Object.entries if you only need own properties.
也就是:
不要只说"不准"
要说"为什么不准"和"怎么安全替代"
这对 AI 也很重要。AI 看到明确原因,更容易做正确修复,而不是机械替换。
9. AI Code Review 应该补上 ESLint 做不到的部分
ESLint 看不到真正业务语义。
比如它不知道:
审批页和查看页是否需要一致
接口字段是否是后端契约字段
这些要靠 AI review。
在 复杂系统里,AI review 应该重点看:
接口调用链
状态机推进
权限条件
路由入口
编辑/查看/审批一致性
字段来源
旧数据兼容
是否误改 backend payload
ESLint 不应该试图解决这些问题。
它只需要把确定性错误挡住,让 AI 和人类把精力放到业务风险上。
10. 老项目怎么落地
对于老 Vue2 项目,不建议一步升级到 ESLint 9。
更现实的路径是:
第一步,恢复 lint 基线:
先让全量 lint 能跑通
第二步,区分规则价值:
哪些规则防 bug
哪些规则只是风格
哪些规则经常诱导机械改写
第三步,放宽高噪音规则:
lua
prefer-destructuring
no-plusplus
ForOfStatement 限制
过严 max-len
第四步,引入 Prettier:
格式交给机器,不进入 review
第五步,升级 parser:
java
babel-eslint -> @babel/eslint-parser
Vue2 保持 vue-eslint-parser
TS 模块逐步接 @typescript-eslint
第六步,把 AI review 固化成流程:
每次业务改动必须说明:
影响入口
接口字段
显示条件
提交 payload
验证方式
这比单纯多开几个 ESLint 规则有用得多。
11. 最重要的判断标准
AI 时代,一个好的 ESLint 报错应该满足:
看到报错,人和 AI 都知道这里大概率真有风险。
如果一个规则经常导致:
代码没风险,但必须换一种写法
那它就应该降级、关闭,或者交给 Prettier。
因为 AI 可以很快修掉 100 个 lint error,但如果其中 80 个只是风格噪音,真正危险的 20 个反而被淹没。 审查注意力被稀释了。
如果一次 PR 里 80 个是缩进、分号、单引号、对象换行,20 个是 for...in、v-model、break、异步提交锁、条件表达式这种可能影响行为的改动,AI 很容易只看到"lint 批量修复",不会逐个判断那 20 个是否改变了业务语义。
12. 结论
AI 时代的 ESLint 不是越严格越好。
更好的方向是:
更少风格争论
更强 bug 信号
更懂现代语法
更少误报崩溃
更适合 AI 自动修复
一句话:
ESLint 应该成为 AI 写代码的安全护栏,而不是风格洁癖的绊脚石。
工具链应该把确定性错误挡住,把格式自动化,把业务语义留给测试、人和 AI review。