news 2026/9/19 12:58:03

eslint-plugin-unicorn 规则实战:prefer-set-size —— 用 `Setsize` 替代 `Arraylength`

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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-unicorn

本篇文章以 eslint-plugin-unicorn 项目中prefer-set-size规则的文档、源码实现与快照测试为依据,系统讲解该规则的核心原理、自动修复行为与边界处理。读完你将掌握:什么代码会被该规则报告、[...set].lengthArray.from(set).length两种模式的修复逻辑、哪些特殊情况会被安全跳过,以及如何通过 ESLint 的--fix一键完成替换。

规则概览

prefer-set-size是 eslint-plugin-unicorn(GitHub 推荐项目精选 / es / eslint-plugin-unicorn,提供 300+ 条 ESLint 规则)中一条专注于 JavaScriptSet用法的规则。其核心主张来自官方文档 docs/rules/prefer-set-size.md:

Set#size是获取Set中元素数量的直接方式。为了读取.length而把Set转成数组是低效的,也违背了使用 Set 的初衷。size属性是 O(1) 的,且不需要任何转换。

从规则元信息(rules/prefer-set-size.js)可以看到它的定位:

  • 类型suggestion(建议型)
  • 可自动修复fixable: 'code',支持 ESLint 的--fixCLI 选项
  • 推荐配置recommended(✅)与unopinionated(☑️)
  • 适用语言js/js
  • 报错信息Prefer using \Set#size` instead of `Array#length`.(消息 ID 为prefer-set-size`)

典型反模式:两种会被报告的写法

根据规则源码中的getSetNode函数(rules/prefer-set-size.js),该规则只针对两种具体的 AST 形态:

1. 展开语法 +length[...set].length

// ❌ 触发规则 function isUnique(array) { return [...new Set(array)].length === array.length; } // ✅ 正确写法 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;

2.Array.from+lengthArray.from(set).length

// ❌ 触发规则 Array.from(new Set(array)).length; // ✅ 正确写法 new Set(array).size;

检测条件非常严格:Array.from必须恰好只有一个参数argumentsLength: 1),且不允许可选调用/可选成员访问(optionalCall: falseoptionalMember: false)。因此Array.from(new Set(array), mapFn).lengthArray?.from(...).lengthArray.from?.(...).length都不会被报告。

触发条件与识别机制

外层必须是成员表达式.length

规则的create函数监听MemberExpression节点(rules/prefer-set-size.js),要求:

  • property严格为length
  • 不允许可选访问(optional: false),因此[...set]?.length会被跳过;
  • 必须是字面属性访问,因此[...set]["length"][...set][length](计算成员)也都会被跳过。

内部必须是真正的Set

仅凭语法形态还不够,规则通过isSet()工具(rules/utils/is-set.js)做类型判定。该工具基于createBuiltinTypeCheckers(rules/utils/type-helpers.js)实现,将类型收敛为三种:target(确定是 Set)、non-target(确定不是)、unknown(无法确定)。其识别能力包括:

  • 字面构造new Set(...)直接判定为目标;
  • 变量追踪const foo = new Set([]); [...foo].length会沿作用域链追踪变量定义(resolveIdentifierName),确认foo是 Set;
  • TypeScript 类型标注:对Set<string>ReadonlySet<string>等类型注解同样识别(ReadonlySet被注册为Set的别名);
  • 排除反例new NotSet(...).length[...Set(array)].length(函数调用而非构造)、let foo = new Set([]); [...foo].length(可重新赋值的变量)、解构绑定的foo、重复var声明等,均被判定为non-targetunknown而跳过。

数组元素必须是单一的展开元素

[...set].length形态还要求数组表达式elements.length === 1且唯一元素是SpreadElement。因此[...new Set(array), foo].length[foo, ...new Set(array)].length不会被误报。

自动修复:快照测试逐项验证的边界行为

快照文件 test/snapshots/prefer-set-size.js.md 记录了 20 个 invalid 用例的完整「输入 → 报错 → 修复输出」对照,来源是测试文件 test/prefer-set-size.js。以下按修复要点分类说明。

基础替换:.length.size

最简单的场景,直接把属性名替换并删除多余的数组展开:

输入: [...new Set(array)].length 输出: new Set(array).size
输入: Array.from(new Set(array)).length 输出: new Set(array).size

变量场景:保持赋值与引用结构

当 Set 已绑定到变量时,修复只替换读取处,不动声明处:

输入: const foo = new Set([]); console.log([...foo].length); 输出: const foo = new Set([]); console.log(foo.size);
输入: function getSize(set: Set<string>) { return Array.from(set).length; } 输出: function getSize(set: Set<string>) { return set.size; }

多余括号:修复后同样得到清理

规则能识别并剥离[...(( new Set(array) ))](( [...new Set(array)] )).length(( Array.from(new Set(array)) )).length等冗余括号层级:

输入: [...(( new Set(array) ))].length 输出: new Set(array).size
输入: (( [...new Set(array)] )).length 输出: (( new Set(array) )).size

注意最后一例:最外层的括号属于数组表达式外层、与成员访问连写((( ... )).length),修复后保留,因为去掉会改变语义。

注释保留

数组内或newSet之间的注释在修复中会被完整保留:

输入: [/* comment */...new Set(array)].length 输出: new Set(array).size 输入: [...new /* comment */ Set(array)].length 输出: new /* comment */ Set(array).size

实现上,createFix会对比arrayset内部包含的注释数量(sourceCode.getCommentsInside,rules/prefer-set-size.js):若被删除的数组表达式内部注释多于set内部的注释,则放弃自动修复(只报错不修),避免丢失注释。

括号补全:TypeScript 类型断言场景

修复的核心动作是「把set文本替换为成员表达式的对象」。当set是 TypeScript 类型断言(如set as Set<string>)时,直接拼成set as Set<string>.size会解析出错,因此规则调用shouldAddParenthesesToMemberExpressionObject(rules/utils/should-add-parentheses-to-member-expression-object.js)判断是否需要加括号:

输入: function getSize(set: unknown) { return [...(set as Set<string>)].length; } 输出: function getSize(set: unknown) { return (set as Set<string>).size; } 输入: function getSize(set: unknown) { return Array.from(set as Set<string>).length; } 输出: function getSize(set: unknown) { return (set as Set<string>).size; }

该工具按节点类型分策略:IdentifierCallExpressionTemplateLiteral等作为成员对象本就安全,返回falseNewExpression仅在已有括号时安全;其他类型(含 TS 断言)默认需要补括号。这条规则同样适用于no-unused-builtin-method-returnno-loop-iterable-mutation等复用isSet的其他规则。

关键字空格修复

[...set].length场景中,array被替换为new Set(...)后,可能出现return new Set(array).size这种关键字(return)与新表达式紧贴的情况。因此createFix在数组表达式分支额外调用fixSpaceAroundKeyword(rules/fix/fix-space-around-keywords.js):检测替换范围前后的 token,若前/后是纯小写关键字(或ofawait)且与范围紧邻,就插入一个空格。

输入: function isUnique(array) { return[...new Set(array)].length === array.length } 输出: function isUnique(array) { return new Set(array).size === array.length }

语句开头场景

当数组表达式出现在语句开头(前面有分号)时,修复同样正确衔接:

输入: foo ;[...new Set(array)].length 输出: foo ;new Set(array).size

如何在自己的项目中使用

该规则属于插件的一部分,无需单独配置。在你的 ESLint 配置中启用unicorn/prefer-set-size即可:

{ "plugins": ["unicorn"], "rules": { "unicorn/prefer-set-size": "error" } }

由于规则fixable: 'code',可以直接用 ESLint 的--fix自动修复:

npx eslint . --fix

如果你使用插件提供的recommendedunopinionated预设配置,该规则会自动启用。执行前建议先运行不带--fix的检查(npx eslint .)预览报告,再决定是否一键修复。

总结

prefer-set-size规则针对 JS 开发中常见的「把 Set 转成数组数长度」反模式,提供了完备的检测与安全自动修复:它严格限定.length成员访问与单一展开元素/单参数Array.from两种形态,通过isSet类型推理避免误报,并在修复时妥善处理括号、注释、关键字空格与 TypeScript 类型断言。其 20 个快照测试用例(test/snapshots/prefer-set-size.js.md、test/prefer-set-size.js)完整覆盖了这些边界行为,可以作为理解规则行为边界的权威参考,也方便你在接入该规则前评估其影响范围。

【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 12:56:37

Hook是什么?一文看懂从Git到YOLOv8的钩子机制

你可能已经无数次在代码、报错日志或者某篇技术文章里见过 Hook 这个词&#xff0c;但每次查资料感觉都像在看黑话。今天我用最直接的方式把这件事讲清楚。Hook 翻译成“钩子”其实挺形象的&#xff1a;它就是程序运行过程中提前预留的挂钩点。你往这个点上挂一段自己的代码&am…

作者头像 李华
网站建设 2026/9/19 12:55:47

DeepSeek Harness 插件接不上模型?TaoToken 这样改 Base URL 字段

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/19 12:54:34

揭秘CogVideoX时空压缩核心:3D因果VAE无损重建原理深度解析

揭秘CogVideoX时空压缩核心&#xff1a;3D因果VAE无损重建原理深度解析 【免费下载链接】CogVideo-code text and image to video generation: CogVideoX (2024) and CogVideo (ICLR 2023) 项目地址: https://gitcode.com/zai-org/CogVideo-code CogVideoX 是智谱 AI 开…

作者头像 李华