资讯动态

eslint-plugin-unicorn 规则实战:no-error-property-assignment 禁止改写内置错误属性

发布时间:2026/9/18 18:05:24 来源:尧图企业网站定制
eslint-plugin-unicorn 规则实战no-error-property-assignment 禁止改写内置错误属性【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicornno-error-property-assignment是 eslint-plugin-unicorn 中用于拦截「在错误对象构造完成之后再向其内置元数据属性赋值」这一反模式的规则。本文以 规则文档 为主体结合 规则源码、内置错误清单 与 测试用例讲解该规则的触发条件、允许场景、实现原理与启用方式帮助你理解为什么不应覆盖name、stack、cause、AggregateError#errors等属性以及如何用构造器参数或应用自定义属性替代。规则解决的问题JavaScript 内置的Error构造器在创建错误对象时会初始化并暴露一组元数据属性例如name错误类型名称stack调用栈信息cause错误链中的底层原因ES2022AggregateError#errors聚合错误的子错误数组。这些属性承载了错误对象的核心语义。如果在构造完成之后再去覆盖它们很容易让日志、堆栈追踪或错误处理逻辑产生误导。例如下面的代码会丢掉真正的调用栈或者把错误的类型标签改得与真实构造器不一致// ❌ 覆盖了 name让日志中的错误类型与真实构造器不符 Object.assign(new Error(message), {name}); // ❌ 覆盖了 stack丢失真实调用栈信息 const error new Error(message); error.stack stack; // ❌ 覆盖了 AggregateError 的子错误数组 Object.assign(new AggregateError(errors, message), {errors});规则要点哪些属性被禁止赋值从 源码实现 可以看到规则维护了两份属性集合通用错误属性errorPropertiesname、stack、cause聚合错误专属集合aggregateErrorProperties在通用集合基础上额外包含errors。即当目标对象是内置错误时name、stack、cause一律禁止赋值只有目标对象是AggregateError时errors才被纳入禁止范围普通Error上的errors属性不受限制。规则的报错信息为Do not assign to{{property}}on a built-in error.允许的写法并非所有对错误属性的写入都会被拦截。下面这些写法是规则明确放行的见 测试用例中的 valid 部分// ✅ 目标不是已知的内置错误实例例如来自外部函数返回的 error 变量 Object.assign(error, {name}); // ✅ code 等应用自定义属性不在禁止清单内 Object.assign(new Error(message), {code}); // ✅ message 是构造器支持的参数未被列入禁止集合 const error new Error(message); error.message message;规则的核心判断标准是「目标对象是否为语法上可确认的内置错误实例」如果你构造了一个Error随后又用普通对象覆盖了该变量规则会基于数据流追踪结果放弃报告同理来自函数返回、解构赋值或自定义子类的变量也不会被报告详见下文实现原理。设计边界只认语法可确认的内置错误规则文档明确强调了一个重要边界This rule intentionally only checks error values that are syntactically known to be built-in errors. It does not infer unknown variables namederroror custom error subclasses.也就是说该规则刻意不做类型推断只处理能在语法层面直接确认的两种情况直接以全局内置错误构造器创建的对象例如new Error()、Error()、new TypeError()通过变量追踪能够确认「该变量一定持有内置错误实例」的情况例如const error new Error()之后对error.name的赋值。变量的名字叫不叫error并不重要自定义错误子类如class CustomError extends Error内部对this.name的赋值也不会被误报——因为this不是语法上可确认的内置错误实例。测试用例中的这一段就是典型验证class CustomError extends Error { constructor() { super(); this.name CustomError; // ✅ 不报告 } }源码实现原理规则源码 主要处理两类写入模式并维护一套跨作用域的变量追踪机制。模式一Object.assign批量赋值通过isMethodCall检查Object.assign(target, ...sources)要求至少两个参数、且Object必须是全局引用然后解析target是否已知为内置错误遍历各个 source 对象字面量ObjectExpression的属性若属性名支持标识符、字符串字面量与计算键命中禁止集合则报告该属性见getObjectAssignProblems源码位置。// ❌ 都会报告 Object.assign(new Error(), {code}, {name}); // name 命中 Object.assign(new Error(), {stack: stack}); // 字符串键也命中 Object.assign(new Error(), {[cause]: cause}); // 计算键同样命中如果 source 不是对象字面量例如变量source或展开对象{...source}规则无法静态确认其内容因此不报告——这与「只处理语法可确认内容」的边界一致。模式二直接属性赋值通过AssignmentExpression与isMemberExpression检查error.prop value形式的赋值解析左侧成员表达式的对象是否为已知内置错误再判断属性名是否命中禁止集合见getDirectAssignmentProblem源码位置。error[name]这种带引号的写法同样会被识别而计算属性error[computed] name因属性名不确定而被放行。内置错误清单判断「是否内置错误」依赖 rules/shared/builtin-errors.js 中维护的全局构造器名单[Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError, AggregateError, SuppressedError]并且要求调用点处该名称是全局引用context.sourceCode.isGlobalReference(node.callee)。这一点很关键如果代码里自行定义了名为Error的局部变量并new之规则不会误报——测试用例中const Error function () {}; error.name name;就是 valid 场景。跨作用域的变量追踪为了识别「先const error new Error()稍后再error.name ...」这类间接赋值规则维护了一个基于帧frame的追踪栈。每进入一个BlockStatement、StaticBlock或SwitchCase就压入一帧函数体块标记为函数边界退出时弹出见 create 函数。变量声明与赋值会写入当前帧的knownErrorVariables映射读取时按栈顺序回溯。此外还区分了「无条件赋值」normal与「条件赋值」conditional只有 normal 模式且操作符为时才会把右侧构造器信息记录为已知内置错误if、while、for等条件分支中的赋值不会污染后续的判断从而避免误报。TypeScript 语法支持规则对 TypeScript 的支持是纯语法层面的通过unwrapTypeScriptExpression解开as断言与satisfies表达式因此下面的写法会被正确识别见 测试用例// ❌ 报告 const error new Error() as Error; error.name Custom; // ❌ 报告 (new Error() as Error).stack stack; Object.assign(new AggregateError([], message) satisfies AggregateError, {errors});但规则刻意不借助 parser services 做类型感知分析——因为名为Error的类型可能描述子类或来自别处的返回值类型感知会超出「已知内置实例」的边界并使结果依赖具体类型配置。这一点与源码中的注释说明完全一致。如何启用规则文档头部的配置徽章标明该规则默认启用自recommended与unopinionated两套配置。安装并启用插件后最直接的用法是在 ESLint flat config 中引入插件与推荐配置import eslintPluginUnicorn from eslint-plugin-unicorn; export default [ eslintPluginUnicorn.configs[flat/recommended], // 或使用更宽松的 unopinionated // eslintPluginUnicorn.configs[flat/unopinionated], { rules: { un/no-error-property-assignment: error, }, }, ];需要留意一个前提规则要求Error等构造器在代码中是全局引用。插件的 configs/flat-config-base.js 通过globals.builtin声明了全局内置对象因此使用插件的推荐配置时这些全局名称是可见的如果你只单独启用该规则而未配置globalsESLint 的no-undef等规则或语言选项可能影响全局引用的判定实际使用时应以插件配置为基准。规则的注册入口位于 rules/index.jsmeta 信息type: problem、recommended: unopinionated、schema: []仅支持js/js语言可在此确认规则本身不提供任何可配置选项。测试验证与建议的修复方式test/no-error-property-assignment.js 通过快照测试覆盖了大量正反用例包括Object.assign的多种键写法、变量声明/赋值/条件分支/switch/for循环/块级作用域/var提升、函数边界、TypeScript 断言等场景是理解规则判定逻辑的最佳参考资料。从这些用例可以总结出推荐的修复策略在构造错误时传入构造器支持的参数message、causeES2022 起new Error(message, {cause})等本就应通过构造器设置使用应用自定义属性code、status等业务字段不在禁止清单内可安全赋值用于携带额外信息若确需自定义类型名优先考虑自定义错误子类并借助custom-error-definition规则规范写法而不是事后改写内置name属性。小结no-error-property-assignment通过「只拦截语法可确认的内置错误实例」的克制设计精准打击了覆盖name/stack/cause/AggregateError#errors的高风险反模式同时不误伤自定义子类、外部来源的error变量和应用自定义属性。理解它的数据流追踪边界作用域帧、条件赋值区分、全局引用校验以及 TypeScript 纯语法支持方式既能帮你安全地启用该规则也能在你阅读或维护基于 ESLint 的静态检查工具时提供一份可复用的「已知构造器实例追踪」实现范式。【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价