重构遗留的 `x += 0` 没人敢删?no-useless-compound-assignment 帮你定位并安全清理

发布时间:2026/10/21 2:15:01
重构遗留的 `x += 0` 没人敢删?no-useless-compound-assignment 帮你定位并安全清理
重构遗留的x 0没人敢删no-useless-compound-assignment 帮你定位并安全清理【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn一次例行重构之后代码库里多出一行total 0;。它不影响运行但没人敢删——万一背后有玄机呢其实这类「恒等复合赋值」绝大多数是纯粹的残留物。eslint-plugin-unicorn 提供的no-useless-compound-assignment规则就是为此而生自动找出这类不改变数值的赋值语句并告诉你安全清理的正确姿势。能力全景一张只有五张「罚单」的质检单这条规则管的范围非常窄只有当复合赋值的右操作数恰好是「该运算的恒等值」时才判定为无意义操作。规则源码 里用一张noOpAssignments映射表锁定了全部命中组合运算符触发值命中示例0total 0-0count - 0*1price * 1/1ratio / 1**1base ** 1除此之外下列写法全部豁免一眼就能建立全局印象所有位运算符|、^、、、、取模恒等值x % 1逻辑赋值||、、??与普通赋值x 0右值不是纯数字字面量的所有情况变量、函数调用、BigInt、带符号写法、TS 断言换个角度看它就像一个只查五种证件的安检员不在名单上的一律放行。判定边界拆解四类被刻意放过的写法及原因为什么豁免项这么讲究每一条背后都有明确理由。① 位运算强转惯用法。x | 0、x 0、x -1这类写法在性能敏感代码里是刻意为之的 int32/uint32 强转手段是「技巧」而不是「失误」。源码注释直接写明了排除动机。②% 1看起来像恒等实际不是。x % 1得到的是 x 的小数部分而不是 x 本身——除以 1 不变取余 1 会「截」掉整数位两者语义完全不同。③ 非算术复合赋值不在射程内。x || 0、x 1、x ?? 0以及普通赋值x 0无论值是否「看起来没意义」规则一概不碰。④ 右值必须能被静态确认为「纯数字字面量」。这是边界的核心源码借助 isNumericLiteral判断node.type Literal typeof node.value number做硬校验因此以下写法全部放行BigIntx 0n——类型不同语义也不同一元符号包裹x -0、x * 1——在 AST 中是UnaryExpression而非Literal且-0的行为并不总是恒等变量与调用x y、x foo()——运行时的值无从判断TypeScript 断言x 0 as number——节点是TSAsExpression不是纯字面量。值得注意的是字面量的「等价形态」逃不掉0.0、1.0、0x1、0e3一样会被标记。因为 AST 保存的是规范化后的数字0或1只是报错信息里会原样展示你写的原始文本比如 0.0。那为什么x * 0、x / 0不报因为它们根本不是恒等操作——乘 0 会把值清零除以 0 得到Infinity值确实被改变了。核心设计取舍为什么只给建议、不直接帮你删「既然恒等删掉不就完了」——不能。因为复合赋值的实际效果取决于左值在运行时的真实状态存在一批看似无操作、实则改状态的极端场景a 0; // 变成字符串拼接产出 a0 5 * 1; // 字符串被隐式转成数字 5 5n * 1; // BigInt 与 Number 混算直接抛 TypeError // x 为 -0 时x 0 会把 -0 翻成 0IEEE 754 有符号零 也就是说规则只能确认「这大概率是死代码」无法确认「删掉一定等价」。于是 规则元数据 只声明了hasSuggestions: true不提供fix错误照常上报但清理动作以编辑器建议的形式摆出来等你亲手点确认。这一步把「自动改写」降级为「人工确认」是对运行时语义差异的保守让步。修复形态两种建议各有一套触发条件确认报错后规则会看赋值表达式在 AST 中的上下文二选一删除整句。当赋值是独立语句ExpressionStatement且直接挂在Program、BlockStatement、StaticBlock、SwitchCase之下时建议「Remove the useless assignment」。底层调用 removeStatement 助手连带吸收本行缩进与换行符不留空行且语句之外的尾随注释会保留——x 0; // keep清理后注释还在。替换为左值。当赋值结果被外部使用时整行删除会破坏语义此时建议把整个赋值表达式换成左值文本foo(x 0)→foo(x)return count - 0→return countconst y (x * 1)→const y xfor (let i 0; i n; i 0) {}→ 更新式变为i左值即使是成员表达式也没问题this.count - 0、foo.bar.baz * 1都能正确取文本。还有一个隐蔽的边界注释卡在赋值内部时规则只报错、不出建议。比如x /* keep */ 0;无论删句还是替换都会吞掉这段注释于是规则宁可保守把清理工作留给人。实战对照错 → 对// ① 独立语句 → 采纳「删除整句」建议 let total getTotal(); total 0; // ✅ 清理后只剩上一行 // ② 结果被 return 使用 → 采纳「替换为左值」建议 function report() { return count - 0; // ✅ 清理后为 return count; } // ③ 注释位于赋值内部 → 只报错、无建议手动清理 x /* keep */ 0;对照 官方文档 的示例与 快照文件可以逐条验证上面每个判定分支的真实输出。如何启用默认配置即生效接入成本几乎为零该规则同时启用在recommended与unopinionated两套预设中文档头部以 ✅ / ☑️ 标注使用插件预设配置时开箱即得元数据为type: suggestion定位是「不掺杂强烈风格偏好」的规则不接收任何自定义选项——五种恒等组合是硬编码的也不开放配置开关。在 readme.md 的规则总表中它以 标记归类于「提供编辑器建议」的规则一族。小结一套可移植的「三步走」实现模式这条规则的参考价值不在规则本身而在它的工程范式拆开来正好三步恒等判定窄化把「什么是无操作」固化为一张小小的映射表且右值只认纯字面量——判定面越窄误报率越低上下文分诊动手前先看父节点决定「能删」还是「必须保留」再选删除或替换策略让建议天然适配所在语句保守落地运行时语义可能不同的场景一律降级为建议而非自动修复注释无法保全时宁可只报错不出修复。「判定恒等 → 区分上下文 → 保守修复」这条流水线对任何想做冗余代码安全清理的静态分析工具都是可以直接抄作业的骨架。【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考