eslint-plugin-unicorn 之 prefer-set-methods 规则全解析:用现代 Set 方法替代展开与过滤模式
eslint-plugin-unicorn 之 prefer-set-methods 规则全解析用现代 Set 方法替代展开与过滤模式【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn导读prefer-set-methods是 eslint-plugin-unicorn 中一条面向集合运算的现代化规则当代码通过数组展开new Set([...a, ...b])、过滤[...a].filter(value b.has(value))或成员检测[...a].every/some(...)来拼装Set、判断集合关系时规则会提示并自动改写为原生的Set#union()、Set#intersection()、Set#difference()、Set#isSubsetOf()、Set#isDisjointFrom()等方法。阅读本文后你将掌握该规则覆盖的全部检测模式、自动修复与建议suggestion的区别、TypeScript 类型感知机制以及其源码级实现原理。本文以该规则在 test/snapshots/prefer-set-methods.js.md 中的 AVA 快照报告为主体素材结合 规则实现、官方文档 与 测试用例 展开讲解。规则定位与启用方式prefer-set-methods被标记为type: suggestion、fixable: code且hasSuggestions: true属于 ✅recommended配置默认开启的规则在 ☑️unopinionated配置中禁用。这意味着大部分场景可通过 ESLint 的--fix直接自动修复涉及语义取舍的场景只给出可手动采纳的编辑器建议suggestion不会强行改动代码。规则的核心目标用官方文档的话说是PreferSetmethods for Set operations原生集合方法直接表达集合运算语义避免书写临时数组与逐成员判定的循环代码更短、意图更清晰、可读性更强。五大检测模式与快照实测快照报告中按场景划分了大量 invalid 用例每条都记录了完整输入、报错位置、报错消息与修复输出。下面按规则实现中的消息 ID 分类逐一解读。模式一Set 展开合并 →Set#union()规则检测new Set([...a, ...b, ...])形式只要数组字面量中的每个展开元素都被确认是Set或ReadonlySet就替换为链式union()调用// ❌ 快照 invalid(1) const a new Set(); const b new Set(); new Set([...a, ...b]); // ✅ 自动修复输出 const a new Set(); const b new Set(); a.union(b); // ❌ 快照 invalid(2)三个集合 new Set([...a, ...b, ...c]); // ✅ a.union(b).union(c);值得注意的细节条件表达式操作数new Set([...(condition ? a : b), ...c])会被修复为(condition ? a : b).union(c)规则会保留条件表达式的括号以维持语义快照 invalid(3)。内联构造new Set([...(new Set()), ...(new Set())])会被修复为(new Set()).union((new Set()))对new Set()这种无副作用操作数同样适用快照 invalid(6)。语句起始位置自动补分号当修复结果出现在表达式语句开头时规则会前置分号避免 ASI 陷阱例如快照 invalid(5) 的输出为;(condition ? a : b).union(c);。模式二过滤交集 →Set#intersection()当代码用[...set].filter(value otherSet.has(value))求交集时规则建议改写为set.intersection(otherSet)// ❌ const a new Set(); const b new Set(); [...a].filter(value b.has(value)); // ✅ 建议输出 a.intersection(b);快照中该模式的典型修复形态是suggestion建议而非直接 fix报告里显示Suggestion 1/1: Use Set#intersection().这是因为裸filter产生的是数组而非Set语义上存在从数组变成 Set 对象的类型差异规则选择让开发者显式确认详见下文自动修复与建议的边界一节。模式三过滤差集 →Set#difference()与交集对称[...set].filter(value !otherSet.has(value))求差集建议改写为set.difference(otherSet)// ❌ const a new Set(); const b new Set(); [...a].filter(value !b.has(value)); // ✅ 建议输出 a.difference(b);快照 invalid(22)/invalid(23) 还覆盖了new Set([...(condition ? a : b)].filter(...))的复合形态输出为;(condition ? a : b).difference(c);与;(condition ? a : b).intersection(c);——注意即使集合源是条件表达式规则也能正确识别并加括号、加分号。模式四成员检测谓词 →isSubsetOf/isDisjointFrom这是快照中占比最大的分组对展开数组调用every/some并配合has判断集合关系。规则实现用一张映射表完成方法推导见 rules/prefer-set-methods.js 中predicateMethodsByArrayMethodevery has → set.isSubsetOf(otherSet) every !has → set.isDisjointFrom(otherSet) some has → !set.isDisjointFrom(otherSet) some !has → !set.isSubsetOf(otherSet)快照中的对应实测// ❌ every has [...a].every(value b.has(value)); // ✅ a.isSubsetOf(b); // ❌ every !has [...a].every(value !b.has(value)); // ✅ a.isDisjointFrom(b); // ❌ some has有交集 [...a].some(value b.has(value)); // ✅ !a.isDisjointFrom(b); // ❌ some !has不完全是子集 [...a].some(value !b.has(value)); // ✅ !a.isSubsetOf(b);这里的every/some是直接修复fix而非建议因为布尔结果类型一致。但规则非常谨慎地处理了否定与运算符优先级!a.isDisjointFrom(b) ** 2、(!a.isDisjointFrom(b)).toString()、!a.isDisjointFrom(b) other等输出都验证了负号取反后必要时的括号包裹逻辑快照 invalid(6)、invalid(5)、invalid(8)。甚至![...a].some(...)这种双重否定会被规范为!!a.isDisjointFrom(b)。模式五空集判断 →size比较优化规则还检测已使用原生集合运算后的空集判断将a.intersection(b).size 0与a.difference(b).size 0提升为关系谓词// ❌ 交集为空 → 不相交 a.intersection(b).size 0; // ✅ a.isDisjointFrom(b) a.intersection(b).size ! 0; // ✅ !a.isDisjointFrom(b) a.intersection(b).size 0; // ✅ !a.isDisjointFrom(b)正向非空同样支持 // ❌ 差集为空 → 子集 a.difference(b).size 0; // ✅ a.isSubsetOf(b) a.difference(b).size ! 0; // ✅ !a.isSubsetOf(b)官方文档明确说明严格不等! 0、反转比较0 a.intersection(b).size以及正向大小比较 0/0 ...都被支持其中严格不等与正向比较会对谓词取反。快照中还包含foo((a.intersection(b).size) (0))这种带括号的包裹形式以及(a.intersection(b).size ! 0).toString()、!(a.intersection(b).size 0)等复合表达式全部都能正确降级为谓词调用。自动修复与建议suggestion的边界理解该规则行为的关键在于区分哪些场景走fix、哪些场景只给suggestion。规则源码给出了明确答案union场景可自动修复但附加严格前提isSetSpreadArray要求数组至少两个元素、每个元素都是 Set 展开且每个操作数安全复用——要么是new Set()字面量要么经hasSideEffect(..., {considerGetters: true})验证无副作用见 rules/prefer-set-methods.js 中isSafeUnionOperand。intersection/difference的 filter 模式只提供 suggestion。官方文档解释裸filter产生的是数组直接改成Set方法存在类型语义变化即便new Set([...set].filter(...))这种直接包裹形式也是 suggestion因为intersection()可能改变 Set 的迭代顺序difference()为了与之一致遵循相同的显式选择模型。快照报告忠实呈现了这一设计union 用例显示Output:自动修复结果而 filter 用例显示Suggestion 1/1: ...两者格式不同。测试文件 test/prefer-set-methods.js 末尾还用return/throw/yield三种关键字验证了 suggestion 修复在生成器函数内的正确输出。源码级实现原理消息与匹配入口规则在create中注册了三个监听器见 rules/prefer-set-methods.jsNewExpression走getUnionProblemunion 模式或getSetOperationProblemfilter 包装模式CallExpression走getArrayPredicateProblemevery/some 谓词模式与getSetOperationProblem裸 filter 模式BinaryExpression走getSetSizeComparisonProblemsize 比较模式。所有消息文本集中定义在messages对象中如Use \Set#union() instead of spreading Sets into a new Set.等共 7 个消息 ID均以prefer-set-methods/ 为前缀便于测试断言与用户定位。Set 类型识别语法推断 类型信息规则对操作数是否为 Set的判断复用工具函数isBuiltinSet定义于 rules/utils/builtin-collection-type.js。其推断链路getBuiltinCollectionType支持语法推断new Set()构造、TSAsExpression/TSSatisfiesExpression/TSTypeAssertion类型断言、TSNonNullExpression、ParenthesizedExpression、ConditionalExpression合并两个分支的类型集变量追踪通过findVariable回溯const变量的初始化表达式或读取变量定义的 TypeScript 类型注解类型信息type-aware当启用 TypeScript parser 的projectService时可进一步结合类型信息确认。这就是为什么快照中function foo(a: Setstring, b: Setstring)、ReadonlySetstring、(a satisfies Setstring)、(b as Setstring)、a!等写法都能命中而const Set class {}遮蔽全局 Set、type SetT T[]、从immutable导入的Set、unknown类型等都会在 valid 用例 中被正确放过。回调约束与引用安全谓词与 filter 模式的回调必须满足isSetCallback同步箭头函数、恰好一个标识符参数、该参数在整个回调中只被引用一次references.length 1。成员检测目标通过getSetHasCallObject校验必须是has(value)形式的方法调用且实参与回调参数isSameReference复用 rules/utils/is-same-reference.js支持解包as/satisfies/!等透明包装检测对象自身不能与回调参数同一引用排除value.has(value)这类自引用检测对象必须是内置 Set且求值无副作用同样开启considerGetters。快照中的忽略案例与此一一对应async回调、带多个参数的回调、{ return b.has(value); }块体、解构参数({value})、b?.has(value)可选链、bhas计算属性、b.has(value) value复合条件、注释包裹等都会被跳过见 test/prefer-set-methods.js 的 valid 列表。注释与副作用防护规则对所有场景统一要求被替换节点内部不得包含注释getCommentsInside(...).length 0则放弃避免自动修复吞掉用户注释。同时hasSideEffect的检查保证了类似new Set([...a, ...getSetThatMutatesA()])快照测试中getSetThatMutatesA会改变a这类代码不会被误修复——因为它把集合铺开成快照再合并的语义与直接union不同。TypeScript 支持与类型感知场景从快照与测试可见该规则对 TypeScript 生态做了完整适配类型注解Setstring、ReadonlySetstring均可识别类型别名type Items Setstring; declare const a: Items;可通过变量定义的类型注解追踪到Set类型表达式包装as、satisfies、非空断言!、泛型箭头T extends string(value: T) ...均支持且修复时会保留这些包装如(a as Setstring).isSubsetOf((b satisfies Setstring))、(a!).isSubsetOf(b!)!JSX 上下文div{[...a].filter(value b.has(value))}/div同样可命中并修复为div{a.intersection(b)}/div见 test/prefer-set-methods.js 中的 JSX 用例。如何查看与验证该规则官方文档docs/rules/prefer-set-methods.md 汇总了规则动机、全部示例与设计取舍说明。规则实现rules/prefer-set-methods.js 为完整源码可对照本文逐段阅读。测试与快照test/prefer-set-methods.js 定义了数百条 valid/invalid 用例运行测试生成的新快照会输出到 test/snapshots/prefer-set-methods.js.md对应的二进制快照为test/snapshots/prefer-set-methods.js.snap由 AVA 维护。快照文件本身就是一份极佳的规则行为说明书每条输入对应的报错位置、消息文本与修复/建议输出都一目了然。启用方式项目使用unicorn/prefer-set-methods规则名recommended配置默认开启可直接用 ESLint--fix应用自动修复或通过编辑器 suggestions 逐条采纳 filter 类建议。小结prefer-set-methods的价值在于把集合运算从临时数组与逐成员判定的手写模式中解放出来引导开发者使用表达力更强的原生Set方法。其实现展现了 ESLint 规则工程化的成熟范式严格的类型推断语法 TypeScript 类型信息、完备的副作用与引用安全分析、fix 与 suggestion 的分层设计以及覆盖 1900 余行快照的极端场景测试矩阵。理解这条规则既能帮助你安全地在项目中启用现代化 Set 写法也为阅读 eslint-plugin-unicorn 其他现代化规则提供了良好的切入点。【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →