ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

eslint-plugin-unicorn 的 prefer-set-size 规则:用 `Setsize` 取代 `Arraylength` 的完整指南

eslint-plugin-unicorn 的 prefer-set-size 规则:用 `Setsize` 取代 `Arraylength` 的完整指南 eslint-plugin-unicorn 的 prefer-set-size 规则用Set#size取代Array#length的完整指南【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicornprefer-set-size是 eslint-plugin-unicorn 提供的一条自动修复auto-fixableESLint 规则用于检测并修复先把Set转换成数组、再读取Array#length这类低效写法引导开发者直接使用Set#size属性。本指南将围绕该规则的设计动机、触发条件、修复逻辑、类型推断机制与测试覆盖展开帮助你理解它何时生效、何时刻意跳过以及如何在项目中正确启用并发挥--fix的最大价值。规则概述属性值规则名称prefer-set-size规则 IDunicorn/prefer-set-size规则类型suggestion建议型是否可自动修复✅ 是支持--fix推荐配置✅recommended、☑️unopinionated适用语言js/js规则元数据定义在 rules/prefer-set-size.js 中meta.type为suggestionmeta.fixable为codemeta.docs.recommended为unopinionated表示它属于推荐启用但风格中立的规则。从源码结构看该规则仅监听MemberExpression节点不做复杂上下文分析因此运行时开销很低。为什么应该用Set#size而不是Array#lengthSet#size是获取Set元素个数的直接方式。把Set转换成数组再读取.length会带来双重问题额外开销展开Set[...set]或调用Array.from(set)都需要遍历全部元素并分配新数组属于 O(n) 的拷贝操作违背语义如果只是为了数个数根本没有必要物化出一个完整数组——Set#size是 O(1) 的属性访问不涉及任何转换。文档 docs/rules/prefer-set-size.md 明确指出Converting aSetto an array just to access its.lengthis inefficient and defeats the purpose of using a Set把Set转成数组仅仅为了读.length是低效的也违背了使用Set的初衷。典型反例与正例最经典的去重计数场景// ❌ 展开成数组再读 length function isUnique(array) { return [...new Set(array)].length array.length; } // ✅ 直接读 size function isUnique(array) { return new Set(array).size array.length; }条件判断场景// ❌ const items new Set([1, 2, 3, 4, 5]); if ([...items].length 3) { // do something } // ✅ const items new Set([1, 2, 3, 4, 5]); if (items.size 3) { // do something }独立取值场景// ❌ const uniqueCount [...new Set(userIds)].length; // ✅ const uniqueCount new Set(userIds).size;规则触发条件两种被识别的转换形态规则核心逻辑位于 rules/prefer-set-size.js 的getSetNode()函数。它只匹配MemberExpression且满足属性名为length、非可选访问optional: false这一前提随后从对象表达式中识别出底层Set。当前支持两种转换形态1. 展开语法形态[...set].length要求对象必须是ArrayExpression且恰好只有一个元素、该元素是SpreadElement[...new Set(array)].length // ❌ 触发 [foo, ...new Set(array)].length // ✅ 不触发不止一个元素 [...new Set(array),].length // ❌ 触发尾部逗号不影响从测试用例test/prefer-set-size.js看[...new Set(array), foo].length、[foo, ...new Set(array),].length均属于 valid 用例因为展开后的数组混入了其他元素.length不再等于Set的大小。2.Array.from形态Array.from(set).length要求是Array.from调用且满足调用对象必须是Array非可选成员访问、非可选调用参数个数必须恰好为 1不允许传入mapFn等第二个参数。Array.from(new Set(array)).length // ❌ 触发 Array.from(new Set(array), mapFn).length // ✅ 不触发有第二个参数 Array?.from(new Set(array)).length // ✅ 不触发可选链 Array.from?.(new Set(array)).length // ✅ 不触发可选调用 NotArray.from(new Set(array)).length // ✅ 不触发对象不是 Array源码级原理如何确认对象真的是Set识别出转换表达式后规则还要确认被转换的对象确实是一个Set或ReadonlySet这一步由工具函数isSet()完成。该函数定义在 rules/utils/is-set.js通过createBuiltinTypeCheckers见 rules/utils/type-helpers.js实现const { isTarget: isSet, isKnownNonTarget: isKnownNonSet, } createBuiltinTypeCheckers({ name: Set, aliases: [ReadonlySet], getStaticType, });getStaticType通过静态值判断value instanceof Set ? target : unknown。结合 rules/utils/type-helpers.js 中的类型推断管线isSet()会按以下优先级层层确认类型变量定义追踪通过findVariable回溯const foo new Set([])这类定义解析初始化表达式的静态类型TypeScript 类型注解识别SetT、ReadonlySetT等类型标注typeReferenceAliases把ReadonlySet映射为SetTypeScript 类型检查器当 parser 提供parserServices.program时调用getTypeAtLocation获取精确类型兜底判定以上均无法确认时返回unknown规则不会贸然报告。这套机制保证了规则的低误报率。测试用例中的这些场景全部被视为 valid[...new NotSet(array)].length // 不是 Set [...Set(array)].length // Set 作为函数调用不是 new Set let foo new Set([]);[...foo].length; // let 声明的变量可能被重新赋值 var foo new Set(); var foo new Set(); [...foo].length // 重复声明 Array.from(new Set(array), mapFn).length // 多参数特别值得注意的是let foo new Set([]); [...foo].length不会被报告。从源码看getTypeFromVariable要求definition.parent.kind const才采用初始化表达式的静态类型——let变量可被重新赋值无法保证运行时仍是Set因此规则选择保守跳过。同理for (const foo of bar) console.log([...foo].length)中foo类型无法静态确定也不会误报。自动修复--fix的行为细节规则通过createFix()生成修复器见 rules/prefer-set-size.js--fix时执行两个核心替换把.length属性名替换为.size把整个数组表达式[...set]或Array.from(set)替换为底层set表达式。注释保护修复前会先比较注释数量sourceCode.getCommentsInside(array).length sourceCode.getCommentsInside(set).length时直接放弃修复。也就是说如果数组表达式内部包含比set更多的注释例如[/* comment */...new Set(array)].length修复会丢弃注释导致信息丢失此时规则只报告不自动修复。测试中[/* comment */...new Set(array)].length、Array.from(/* comment */ new Set(array)).length均作为 invalid 用例出现验证了报告但不丢注释的行为。括号自动补全set替换后将变成成员表达式的对象某些表达式作为.size的对象时需要加括号。shouldAddParenthesesToMemberExpressionObject()见 rules/utils/should-add-parentheses-to-member-expression-object.js判断Identifier、MemberExpression、CallExpression、TemplateLiteral等类型无需括号而其他类型如NewExpression、TS 断言需要包裹。典型的 TypeScript 场景// ❌ 修复前 function getSize(set: unknown) { return [...(set as Setstring)].length; } // ✅ 修复后set as Setstring 需要括号才能作为成员访问对象 function getSize(set: unknown) { return (set as Setstring).size; }测试中function getSize(set: Setstring) { return Array.from(set).length; }、function getSize(set: ReadonlySetstring) { ... }均会被报告并可修复证明规则完整支持 TypeScript 类型注解场景。空格规范化当原表达式是数组展开形态array.type ArrayExpression时还会调用fixSpaceAroundKeyword见 rules/fix/fix-space-around-keywords.js规范化关键字周围的空格例如把return[...new Set(array)].length修复为return new Set(array).size避免生成语法或格式不规范的代码。测试覆盖与验证规则配套测试位于 test/prefer-set-size.js使用项目统一的getTester(import.meta)快照测试框架覆盖了三类场景valid 用例验证不误报——非Set类型、多元素展开、可选链、计算属性名[length]、[length]、let/重复声明变量、Array.from多参数等invalid 用例验证必报必修——两种转换形态、注释场景、括号嵌套[...(( new Set(array) ))].length、(( [...new Set(array)] )).length、语句边界foo\n;[...new Set(array)].lengthTypeScript 用例通过parsers.typescript验证类型注解、ReadonlySet、类型断言set as Setstring等场景。运行npx eslint test/prefer-set-size.js或项目测试脚本即可本地复现这些行为。在项目中启用该规则在recommended与unopinionated配置中默认开启无需额外配置。若使用扁平配置flat config可直接引用项目提供的 configs/flat-config-base.jsimport unicorn from eslint-plugin-unicorn; export default [ unicorn.configs[flat/recommended], // 或按需显式启用 { plugins: {unicorn}, rules: { unicorn/prefer-set-size: error, }, }, ];配合 ESLint 命令行--fixnpx eslint . --fix即可让该规则自动改写项目中的[...set].length与Array.from(set).length。需要说明的是规则只在能静态确认对象是Set或ReadonlySet时才报告因此对泛型参数、动态类型等无法确认的场景会安全地保持沉默。小结触发对象[...set].length与Array.from(set).length且set必须是可静态确认的Set/ReadonlySet修复产物直接访问set.size配合括号补全与空格规范化保证修复后代码可读、语义等价安全边界多元素展开、Array.from带映射函数、let变量、注释密度更高的表达式等场景刻意跳过宁可漏报也不误报开箱即用recommended/unopinionated已默认开启--fix全自动修复TypeScript 场景同样适用。将该规则纳入常规 lint 流程可以在不改变任何运行时语义的前提下系统性地消除为取长度而物化数组的低效写法让Set真正发挥其 O(1) 大小查询的能力。【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表