
eslint-plugin-unicorn 的 consistent-conditional-object-spread 规则统一条件对象展开风格【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn导读在 JavaScript/TypeScript 中...(condition ? object : {})与...(condition object)是两种等价的条件对象展开写法混用会让代码风格杂乱无章。eslint-plugin-unicorn 提供的consistent-conditional-object-spread规则建议类、可自动修复用于在整个项目中强制统一其中一种风格默认偏好更简洁的写法。本文基于 规则文档 与 规则源码、测试用例 及快照完整讲解该规则的两种风格、null/undefined回退分支的特殊处理、配置方法、自动修复的边界条件与底层实现原理。规则定位与启用状态consistent-conditional-object-spread是一条专注于对象字面量展开语法的风格一致性规则在 readme 规则总表 中有明确登记类别suggestion建议类不会改变程序运行结果只纠正写法风格自动修复支持 可通过 ESLint 的--fixCLI 选项 自动转换推荐配置在recommended配置中启用✅在unopinionated配置中禁用☑️适用语言从源码meta.languages看仅针对js/js规则源码。该规则只针对对象字面量中的条件展开isObjectSpreadArgument校验了父节点必须是ObjectExpression且当前节点是其中的SpreadElement参数因此数组字面量中的[...(foo ? {bar: true} : {})]不会被误报。两种风格logical 与 ternary规则要求在两种写法中统一其一选项值偏好风格说明logical默认...(condition object)用逻辑与短路展开条件为假时展开false而对象展开对 falsy 值不添加任何属性ternary...(condition ? object : {})用三元表达式显式提供空对象回退分支配置项类型为string默认值为logical这一默认策略在源码的defaultOptions中声明规则源码。为什么默认偏好文档明确解释了默认动机写法避免了一个多余的空对象分支avoids an unnecessary empty object branch。同时no-useless-fallback-in-spread 也指出对象字面量中展开 falsy 值不会添加任何意外属性因此...(foo || {})、...(foo ?? {})中的空对象回退其实是冗余的应直接写作...foo。两条规则在空对象分支是冗余的这一认知上保持一致——既然空分支本身可有可无默认自然偏向不写它的形式。示例详解默认logical风格下的报错与修复// ❌ 违反默认风格 const object {...(condition ? {property} : {})}; // ✅ 符合默认风格 const object {...(condition {property})};从 测试快照 可见实际修复效果由fixer.replaceText完成Input: const object {...(foo ? {bar: true} : {})} Message: Prefer logical conditional object spreads. Output: const object {...(foo {bar: true})}当空分支位于consequent条件为真的一侧时例如{...(foo ? {} : {bar: true})}规则会生成带!的取反条件{...(!foo {bar: true})}。同理{...(!foo ? {} : {bar: true})}会被转换为{...(foo {bar: true})}快照 invalid 2、3 号用例。undefined/null回退分支与空对象等价文档特别强调展开undefined或null同样不会添加任何属性因此它们与空对象{}等价同样会被视为空分支并触发转换// ❌ 违反默认风格 const object {...(condition ? {property} : undefined)}; const object {...(condition ? {property} : null)}; // ✅ 符合默认风格 const object {...(condition {property})};这一语义在源码的isEmptySpreadBranch中实现规则源码// {...{}}, {...undefined}, and {...null} all spread nothing. const isEmptySpreadBranch node isEmptyObjectExpression(node) || isUndefined(node) || isNullLiteral(node);三个辅助函数分别位于 rules/ast/is-empty-object-expression.jsObjectExpression且properties.length 0、rules/ast/is-undefined.jsIdentifier且名为undefined以及 rules/ast/index.js 导出的isNullLiteral。注意边界void 0在 AST 中是UnaryExpression而非undefined标识符因此{...(foo ? {bar: true} : void 0)}不会被视为空分支、不触发报错见 测试用例。同理两个分支都为空foo ? {} : {}、foo ? undefined : undefined时规则不会干预。配置方法在 ESLint 配置中可按需指定风格// .eslintrc 风格 { rules: { unicorn/consistent-conditional-object-spread: [error, ternary] } }// eslint.config.jsflat config风格 import js from eslint/js; import unicorn from eslint-plugin-unicorn; export default [ js.configs.recommended, { plugins: {unicorn}, rules: { unicorn/consistent-conditional-object-spread: [error, ternary], }, }, ];配置值为ternary时规则反过来要求三元写法// eslint unicorn/consistent-conditional-object-spread: [error, ternary] // ❌ 违反 ternary 风格 const object {...(condition {property})}; // ✅ 符合 ternary 风格 const object {...(condition ? {property} : {})};从源码 schema 可知规则源码选项是长度为 1 的数组枚举值仅logical与ternary两个传入其他值会被 ESLint 校验拒绝。create函数根据context.options[0]决定监听LogicalExpression还是ConditionalExpression节点规则源码。自动修复的边界条件何时只报错、不修复该规则在以下情况报告问题但拒绝自动修复这与源码中生成问题对象时对fix函数的分支处理直接对应条件表达式内部存在注释getConditionalExpressionProblem在hasCommentsInside为真时仍会报告但 fix 函数会abort()规则源码。例如{...(foo ? {a: 1} : /* keep */ {})}会被标记但不会自动改写。快照中/* keep */系列的 invalid 用例3438 号都只有消息、没有 Output。逻辑表达式内部存在注释getLogicalExpressionProblem的 fix 同样在发现注释时中止规则源码如快照 invalid 49 号{...(foo /* keep */ {bar: true})}。三元条件两分支类型不一致当isAlternateEmpty isConsequentEmpty两个分支都为空或都不为空时规则直接跳过例如{...(foo ? {bar: true} : {baz: true})}是合法的。条件与保留分支引用相同{...(foo ? foo : {})}、{...(foo.bar ? foo.bar : {})}、async () ({...(await foo ? await foo : {})})等场景下把三元改写为会改变求值语义会对条件求值两次因此规则跳过源码isSameNode递归比较分支规则源码。nullish 防护模式当三元表达式的条件本身就是空值检查、且被保留的分支就是检查对象时如{...(foo null ? {} : foo)}、{...(foo ! null ? foo : {})}、{...(foo null || foo undefined ? {} : foo)}改写反而会破坏语义规则将其视为合法。快照中对应的 valid 用例完整验证了 null、 null、! null ! undefined等各种组合。反过来ternary风格下{...(foo undefined)}、{...(foo foo)}、{...(foo ! null foo)}等也被视为合法语义推理逻辑相同见 测试用例。源码实现剖析从 AST 到修复文本整条规则的核心流程可从 规则源码 中梳理定位目标isObjectSpreadArgument确认当前节点是对象字面量内SpreadElement的直接参数规则源码避免误伤数组展开或嵌套属性访问。空分支判定isEmptySpreadBranch将{}、undefined、null统一视为展开无效果。语义等价性判定getNullishTest解析出foo null、foo ! null、foo null || foo undefined这类 nullish 检查并配合isSameReference实现见 rules/utils/is-same-reference.js会解开?.链式与 TS 的as、satisfies、Type、!包装确认条件引用的就是被展开的对象从而豁免改写。括号处理修复文本生成依赖一组括号工具——shouldAddParenthesesToLogicalExpressionChildrules/utils/should-add-parentheses-to-logical-expression-child.js对AwaitExpression、BinaryExpression、ConditionalExpression等优先级低于的节点补括号、shouldAddParenthesesToConditionalExpressionChild、shouldAddParenthesesToUnaryExpressionArgument与getParenthesizedText。这也是为什么快照中async () ({...(await foo ? {a: 1} : {})})被修复为async () ({...((await foo) {a: 1})})——await在右侧必须加括号。消息文本两种方向分别使用同一消息模板Prefer {{expectedStyle}} conditional object spreads.expectedStyle为logical或ternary规则源码快照中可看到两种消息的实际输出。TypeScript 支持测试覆盖了bar!、foo as string、foo satisfies string、stringfoo等 TS 节点测试用例修复时会对这些表达式整体加括号如{...(!(foo as string) bar)}快照 invalid 21 号。测试覆盖与验证方式规则的测试集中在 test/consistent-conditional-object-spread.js采用快照snapshot模式修复输出记录在 test/snapshots/consistent-conditional-object-spread.js.md。测试矩阵覆盖默认logical方向下 38 组 invalid 用例及其修复结果包括条件在consequent/alternate两侧、!取反、||//??复合条件、序列表达式(a, b)、函数表达式、?.可选链等ternary方向下 11 组 invalid 用例含(a || b) {x: 1}、(a, b) {x: 1}、await foo {a: 1}、赋值与序列表达式作为右操作数、TS 非空断言bar!约 30 组 valid 用例用于锁定不该报错的边界引用相同、nullish 防护、双空分支、数组展开、void 0等。若需在本地验证可运行npm test -- consistent-conditional-object-spread与其他规则的协同no-useless-fallback-in-spread 与本规则互为补充前者处理无条件展开时多余的|| {}/?? {}回退后者统一有条件展开的写法风格该文档末尾也显式引用了本规则链接原文。默认的logical风格配合no-useless-fallback-in-spread共同导向能不写空对象就不写的简洁风格而选择ternary风格的团队则可关闭前者的部分场景保持显式回退的可读性。小结consistent-conditional-object-spread是一条小而精的代码风格规则它把条件对象展开这一高频写法的两种等价形态统一为团队约定默认选择更简洁、少一个空分支的风格并在null/undefined/空对象三者等价、nullish 防护、注释保护、语义保真括号与引用一致性等细节上做了严谨的工程化处理。理解其两种选项、修复边界与源码判定的思路既能直接上手配置也能为阅读和扩展 eslint-plugin-unicorn 其他风格类规则提供参照。【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考