eslint-plugin-unicorn no-useless-compound-assignment 完全指南如何看懂无用的复合赋值【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn一次大型重构收尾后代码里常常残留几行看起来人畜无害的语句total 0;、price * 1;……值没变删了好像也行留着又碍眼。这正是eslint-plugin-unicorn中no-useless-compound-assignment规则要清理的对象当复合赋值右侧恰好是数学恒等值时这条语句大概率是重构的遗迹规则会把它揪出来。这篇文章带你从判定边界讲到源码实现看清它为什么报、为什么不自动改、建议是怎么生成的。规则名片30 秒看懂 no-useless-compound-assignment项目内容规则名no-useless-compound-assignment所属项目eslint-plugin-unicorn300 条 ESLint 规则规则类型type: suggestion属于建议类元数据见第 104 行默认启用✅recommended与 ☑️unopinionated两个配置中都开启修复方式 不提供自动修复仅通过编辑器建议editor suggestions手动应用可配置选项无规则不接受任何自定义参数报错文案This compound assignment is useless as{{operator}} {{value}}does not change the value.一句话定位它是一条死代码清理器专门负责找出那些运算了个寂寞的赋值语句。命中矩阵5 种恒等值复合赋值写法规则的核心逻辑很简单——查一张映射表noOpAssignmentsrules/no-useless-compound-assignment.js 第 20–26 行只有运算符 对应恒等值的组合才会命中运算符必须右侧的值报错示例0x 0-0x - 0*1x * 1/1x / 1**1x ** 1注意运算符和恒等值是一一对应的x * 0、x / 0、x ** 0这类运算符配错恒等值的写法不会命中见 test/no-useless-compound-assignment.js 第 55–58 行 的 valid 用例。为什么0.0、0x1、0e3也照样被抓住判定不看你源码里写的是哪种记法而是看解析后的Literal节点的value属性JS 引擎会把0.0、0e3、十六进制的0x1、1.0等统一规范化成数字0或1于是它们全部通过value 恒等值这一关测试用例见 test/no-useless-compound-assignment.js 第 69–72 行。快照文件 test/snapshots/no-useless-compound-assignment.js.md 里还能看到x 0.0的完整报错输出——错误信息通过node.right.raw原样展示字面量原文所以你看到的是 0.0而不是 0。不命中边界清单这些写法为什么无罪下面逐条列出不会触发规则的情况每条只给结论和一句原因x | 0、x 0、x -1、x 0、x 0、x ^ 0位运算系列作者故意放行这类写法因为它们是社区公认的把值强转为 32 位有符号/无符号整数的惯用手法是刻意为之的意图不是手滑。测试文件里专门给它们安排了一整组 valid 用例第 16–21 行源码注释也写明了这一排除理由。x % 1取模 1 得到的是x的小数部分x % 1并不等于x根本不是无操作所以排除在外。TypeScript 类型断言x 0 as number、x * (1 satisfies number)在 AST 里是TSAsExpression不是纯字面量节点第 52–53 行。非字面量右值x y、x * zero、x foo()的运行时取值无法静态确定规则不做猜测。BigInt 字面量x 0n、x * 1n中的0n不是普通number类型的Literal直接过不了字面量判定这一关。一元正负号包裹x -0、x * 1在 AST 中是UnaryExpression而不是Literal而且-0与0在 IEEE 754 里语义并不相同宁可保守跳过。逻辑赋值与普通赋值x || 0、x 1、x ?? 0、x 0、x 1都不属于算术复合赋值的检测范围。为什么修复必须手动确认而不直接自动改先说现象x 0在纯数字世界里确实是恒等运算但如果左值在运行时的实际值不是数字呢规则文档docs/rules/no-useless-compound-assignment.md 第 18 行列出了四个足以推翻恒等假设的坑字符串拼接a 0的结果是a0字符串和 0 拼一起值彻底变了隐式类型转换5 * 1会把字符串5转成数字5变量的类型都发生了改变有符号零x 0会把-0洗成0而Object.is(-0, 0)是false对依赖Object.is的代码来说是行为变化BigInt 混算直接抛错5n * 1会抛出TypeError删掉这行可能顺带改变了异常路径。也就是说删掉这一行或把赋值换成左值在不同运行时取值下会产生不同的结果。自动修复fix的承诺是改写后行为完全不变这里无法兑现而 editor suggestion 只是把改法摆到编辑器里供你一键确认责任由人承担。于是规则的元数据里只声明了hasSuggestions: true第 109 行没有fixable——这正是文档头部那个 图标的含义manually fixable by editor suggestions。实现走读从 AST 定位到生成建议整个create函数只有约 60 行rules/no-useless-compound-assignment.js流程可以拆成四步第一步AST 定位监听所有AssignmentExpression节点第 34 行先用noOpAssignments.has(node.operator)过滤掉不在五张牌里的运算符提前返回。第二步字面量判定调用 rules/ast/literal.js 第 29 行 的isNumericLiteral助手——判定条件就两半node.type Literal typeof node.value number。BigInt、一元表达式、TSAsExpression都在这一关被筛掉过关后再比较node.right.value是否严格等于该运算符的恒等值第 42–44 行。第三步上下文区分这是两种建议分道扬镳的地方第 51–54 行。规则检查赋值节点的父节点若父节点是ExpressionStatement且语句的容器祖父节点是Program、BlockStatement、StaticBlock或SwitchCase之一——即这条赋值是独占一行、结果无人使用的独立语句——标记为isRemovableStatement。测试覆盖了顶层语句、函数体内缩进语句、switch的case分支、class 静态块四类位置第 89–96 行。否则意味着赋值的结果被使用了比如foo(x 0)、return count - 0、const y (x * 1)、逗号表达式、for循环的更新表达式等整句删掉会破坏语义。第四步生成建议第 56–95 行注释护栏先走用sourceCode.getCommentsInside检查目标范围内有没有注释。如果有例如x /* keep */ 0;或者x * 1/* keep */;这种紧贴分号的尾注释删除或替换都会把它弄丢规则只报错、不给任何建议第 57–59 行对应测试 第 99–110 行。反之x 0; // keep中注释在语句外部删除语句时可以安全保留建议照常给出。可删场景建议文案 Remove the useless assignment.修复函数委托给 rules/fix/remove-statement.js 的removeStatement助手——它会连语句和周围空白一起移除但保留语句之外的尾随注释第 61–76 行。结果被使用场景用sourceCode.getText(node.left)取出左值原文第 79 行建议文案 Replace the useless assignment with{{left}}.修复动作是fixer.replaceText(node, left)——把整个赋值表达式原地换成左值第 84–93 行。左值写成成员表达式也没问题如obj.x、this.count、foo.bar.baz。典型写法对照❌/✅ 最小代码对独立语句 → 建议直接删除整句测试 第 90、93、96 行 分别验证了函数体内、switchcase 内、class 静态块内的版本// ❌ let total getTotal(); total 0; // ✅ let total getTotal();建议会连同total 0;整行含缩进空白一并移除语句尾部的// keep这类外部注释不受影响。结果被使用 → 建议替换为左值// ❌ function f() { return count - 0; } // ✅ function f() { return count; }count - 0在数值上等于count但如前所述仍可能存在-0变0的差异所以以建议形式让你确认。成员表达式左值同理foo(obj.x 0)会建议替换成foo(obj.x)。赋值内部带注释 → 只报错、无建议// ❌ 报错但编辑器不会给出任何建议 x /* keep */ 0;因为任何改法都会吞掉那条注释规则选择放弃建议把决定权留给你。总结检测面很窄只有 0、- 0、* 1、/ 1、** 1五种运算符 × 恒等值组合且右值必须是纯数字Literal0.0/0x1/0e3这类等价写法同样命中。放行面很准位运算强转惯用法int32/uint32 手法、% 1取小数部分、BigInt、一元符号、非字面量右值、TS 断言全部刻意排除宁可不报也不误伤。修复必须经人确认字符串拼接、隐式类型转换、-0 → 0、BigInt 混算抛错这些运行时语义差异让自动删除/替换无法承诺行为不变于是设计成 editor suggestion。建议策略看上下文独立语句给删整句结果被使用给换左值注释落在改动范围内则干脆不出建议。这套先做窄判定、再看 AST 上下文、最后保守出手的思路对任何想在静态分析工具里做安全清理的开发者都有参考价值能确定的边界一定要确定不能确定的代价就交给用户的一键确认。【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?