ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

eslint-plugin-unicorn `prefer-error-is-error` 规则深度解析:用 `Error.isError()` 统一错误对象检测

2026/9/19 2:01:39 拓冰建站 浏览量
eslint-plugin-unicorn `prefer-error-is-error` 规则深度解析:用 `Error.isError()` 统一错误对象检测 eslint-plugin-unicornprefer-error-is-error规则深度解析用Error.isError()统一错误对象检测【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn本篇文章围绕 eslint-plugin-unicorn 中prefer-error-is-error规则的快照测试文档test/snapshots/prefer-error-is-error.js.md展开完整梳理该规则检测的全部 24 个违规场景、自动修复输出并结合规则源码与 AVA 测试用例剖析其底层实现原理。读完本文你将理解instanceof Error与Object.prototype.toString检测错误对象的两大缺陷掌握该规则的触发条件、边界处理变量遮蔽、注释保护、TypeScript 语法以及--fix的精确行为能够自信地在真实项目中启用并解释这条规则。规则背景为什么需要Error.isError()prefer-error-is-error规则的核心主张是检查一个值是否为错误对象时优先使用Error.isError()。其官方文档docs/rules/prefer-error-is-error.md给出了两条关键理由instanceof Error在跨 realmiframe、Web Worker、Node.js vm 等不同全局环境场景下不可靠不同 realm 各自拥有独立的Error构造函数来自另一个 realm 的错误对象无法通过当前 realm 的instanceof Error判定Object.prototype.toString.call(error) [object Error]可以被Symbol.toStringTag伪造任何对象只要定义了[Symbol.toStringTag]为Error就能冒充错误对象。Error.isError()是 ECMAScript 提议proposal-is-error引入的健壮检测方式可以同时规避上述两类问题。该规则的元数据rules/prefer-error-is-error.js将其声明为type: suggestion、fixable: code即通过 ESLint 的--fix命令行选项即可自动修复且规则不带任何可配置项schema: []开箱即用、行为确定。规则整体行为一览从 test/prefer-error-is-error.js 的测试用例可以归纳出规则的两大检测目标这与快照文档中 24 个 invalid 用例一一对应检测目标典型违规写法修复结果instanceof Error判定5 例invalid 1–5error instanceof ErrorError.isError(error)字符串标签比对判定19 例invalid 6–24Object.prototype.toString.call(error) [object Error]Error.isError(error)/!Error.isError(error)其中第一条检测路径只在右操作数为全局Error未被本地变量遮蔽时触发第二条检测路径则要求比对运算符属于、!、、!四种之一且一侧是[object Error]字符串字面量、另一侧是符合特定形态的toString().call()调用。任何形态不匹配的代码例如error instanceof TypeError、比对[object TypeError]都不会被报告。快照中的 24 个违规场景逐类拆解快照文档完整记录了test/prefer-error-is-error.js中每个 invalid 用例的输入源码、报告消息统一为Prefer \Error.isError(…).以及修复后的输出。以下按语义分组逐一说明。第一组instanceof Error形态invalid 1–5这一组覆盖了左操作数的各种表达式形态证明规则不仅匹配标识符还匹配任意表达式用例输入修复输出invalid(1)error instanceof ErrorError.isError(error)invalid(2)(error) instanceof ErrorError.isError(error)invalid(3)getError() instanceof ErrorError.isError(getError())invalid(4)a b instanceof ErrorError.isError(a b)invalid(5)(sideEffect(), error) instanceof ErrorError.isError((sideEffect(), error))值得注意 invalid(5)当参数是逗号表达式SequenceExpression时修复器会保留括号写成Error.isError((sideEffect(), error))。这一细节由源码中的getArgumentText函数保证rules/prefer-error-is-error.jsSequenceExpression类型的节点会额外包裹一对括号避免改变表达式的结合语义。第二组字符串标签比对invalid 6–15Object.prototype.toString.call(...)系列是该规则主战场快照覆盖了运算符方向、运算符种类、调用对象形态与参数形态的多种组合等号与不等号双向判定invalid 6、!invalid 8以及/!invalid 10–11都被识别字面量既可以出现在右侧invalid 6也可以出现在左侧invalid 7、9、11。修复时按运算符取反语义输出/对应Error.isError(error)!/!对应!Error.isError(error)。调用对象等价形态除了标准的Object.prototype.toString.call(error)还支持({}).toString.call(error)invalid 12–13——即一个空的对象字面量直接取toString语义与Object.prototype.toString等价。isEmptyObjectToString与isObjectPrototypeToString两个辅助函数rules/prefer-error-is-error.js共同完成这两种形态的识别。实参形态参数可以是带副作用或逗号表达式(sideEffect(), error)invalid 14修复后括号同样被保留。多行格式化与尾逗号invalid(15) 展示了跨行书写Object.prototype.toString.call(\n\terror,\n)的场景修复后同样规范为单行Error.isError(error)。需要特别说明的是规则对toString调用的识别是严格限定形态的必须是call方法、恰好 1 个实参、不允许可选链这由getToStringCallArgument中isMethodCall(node, {method: call, argumentsLength: 1, optionalCall: false, optionalMember: false})约束实现rules/prefer-error-is-error.js。因此Object.prototype.toString.apply(error)、Object.prototype.toString.call(error, extra)、Object.prototype[toString].call(error)这类变体在 valid 测试中都被明确视为不报告见 test/prefer-error-is-error.js。第三组TypeScript 语法与全局名遮蔽invalid 16–24快照后半部分集中展示了 TypeScript 解析器下的边界行为核心逻辑是类型声明不构成值遮蔽用例输入修复输出invalid(16)error! instanceof ErrorError.isError(error!)非空断言!被原样保留invalid(17)type Error unknown; error instanceof Errortype Error unknown; Error.isError(error)invalid(18)interface Error {}; error instanceof Errorinterface Error {}; Error.isError(error)invalid(19)import type {Error} from error; error instanceof Errorimport type {Error} from error; Error.isError(error)invalid(20)type Error unknown; Object.prototype.toString.call(error) [object Error]type Error unknown; Error.isError(error)invalid(21)type Object unknown; ...照常修复类型别名不遮蔽Objectinvalid(22)import type {Object} from object; ...照常修复invalid(23)Object.prototype.toString.call(error as unknown) [object Error]Error.isError(error as unknown)as断言保留invalid(24)Object.prototype.toString.call(error!) [object Error]Error.isError(error!)这里的判定逻辑由isTypeOnlyDefinition实现rules/prefer-error-is-error.jstype声明、interface声明以及import type {...}导入都属于仅类型定义不会让Error/Object成为被遮蔽的本地值因此规则依然把右侧的Error当作全局构造器处理。反过来说如果存在值级别的声明如const Error CustomError;、class Error {}、function check(Error) {...}或普通import {Error} from errorisValueShadowed会返回 true规则就会放行——这些情况全部收录在 valid 用例中test/prefer-error-is-error.js。自动修复的精确行为规则通过createFix构造修复器rules/prefer-error-is-error.js修复字符串的拼装规则如下${negate ? ! : }Error.isError(${getArgumentText(argument, sourceCode)})对instanceof分支negate恒为false直接替换整个 BinaryExpression对字符串标签比对分支negate取决于运算符!或!时输出!Error.isError(...)其余输出Error.isError(...)rules/prefer-error-is-error.js实参文本取自sourceCode.getText(node)即保留源码原始写法含as断言、非空断言!、逗号表达式括号确保修复不引入额外格式化改动。此外快照 invalid(15) 还展示了跨行节点的替换整个 BinaryExpression 会被整体替换为单行Error.isError(error)自动完成压缩格式化的效果。不触发报告的边界情况快照之外的守护快照文件只记录了 invalid 用例但 test/prefer-error-is-error.js 中的 valid 用例揭示了规则刻意回避的场景理解这些边界对实际使用至关重要注释保护只要 BinaryExpression 内部存在任何注释hasComments检测见 rules/prefer-error-is-error.js规则直接跳过避免--fix删除注释。error instanceof /* comment */ Error、Object.prototype.toString.call(/* comment */ error) [object Error]等均不报告。标签不匹配比对[object TypeError]或其他动态变量tag时不报告。非call形态apply、多参数、零参数、计算结果再切片.slice(8, -1) Error均不报告。值遮蔽本地有Error/Object的值声明时不报告避免错误改写用户自定义语义。可选链与计算属性Object.prototype[toString]、可选调用等形态均被排除。与no-instanceof-builtins规则的协作prefer-error-is-error与unicorn/no-instanceof-builtins规则互补。官方文档明确指出no-instanceof-builtins只处理instanceof内置构造器的问题而本规则额外捕获使用[object Error]字符串标签的旧式错误品牌检测docs/rules/prefer-error-is-error.md。两条规则的启用状态也不同no-instanceof-builtins已加入recommended与unopinionated配置见 docs/rules/no-instanceof-builtins.md而prefer-error-is-error目前在这两套配置中均为禁用状态。其源码中的 TODO 注释揭示了原因rules/prefer-error-is-error.js规则预计在Error.isError()成为 Baseline 标准、且项目目标运行环境支持 Node.js 24 之后才会被纳入recommended配置。也就是说当前启用它需要你在 ESLint 配置中手动开启// eslint.config.js export default [ { rules: { unicorn/prefer-error-is-error: error, }, }, ];若你在使用no-instanceof-builtins且希望错误检测统一走Error.isError()还可以组合其useErrorIsError: true选项见 docs/rules/no-instanceof-builtins.md让两条规则在错误对象检测上口径一致。快照测试机制这份文档是如何生成的本文依托的 test/snapshots/prefer-error-is-error.js.md 是 AVA 测试框架avajs.dev。生成链路如下test/prefer-error-is-error.js 通过getTester(import.meta)获取测试器调用test.snapshot({valid, invalid})注册用例test/utils/test.js中的Tester#snapshot方法将用例交给SnapshotRuleTestertest/utils/snapshot-rule-tester.js后者对每个 invalid 用例运行 Linter记录输入源码、报告消息位置与文本、修复输出三要素结果渲染为 Markdown 快照报告即本关联文档并同步序列化到.snap文件测试运行时 AVA 会对比两者任何行为变化都会触发快照 diff从而把规则行为变更显式暴露在 code review 中。这份快照文档因此既是规则的契约也是理解--fix行为的权威参考文中每一处Output:都对应 ESLint fixer 的真实输出可直接作为回归断言使用。总结prefer-error-is-error是一条无配置、可自动修复的现代化规则针对instanceof Error的跨 realm 缺陷与Symbol.toStringTag伪造问题给出统一答案Error.isError()。快照文档中的 24 个用例完整刻画了它的检测边界既覆盖从标识符到逗号表达式的各种实参形态也妥善处理了注释保护、值/类型遮蔽区分以及 TypeScript 的as、非空断言语法。结合 rules/prefer-error-is-error.js 的源码你可以确信它的每一次修复都是精确、可预期的。在当前Error.isError()尚未进入recommended配置的阶段手动开启这条规则并配合--fix是让代码库尽早对齐标准错误检测语义的低成本选择。【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考