modern-errors

modern-errors

强大而灵活的JavaScript错误处理库

modern-errors是一个功能丰富的JavaScript错误处理库。它简化了错误类的创建、属性设置、错误包装和聚合等操作,并能有效区分已知和未知错误。该库以稳定性著称,拥有全面的测试覆盖和严格的TypeScript类型支持。通过插件系统,modern-errors还可扩展多种功能,如命令行界面错误处理、进程错误管理和错误序列化等。

错误处理异常封装错误类插件系统TypeScriptGithub开源项目
<picture> <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ehmicky/design/main/modern-errors/modern-errors_dark.svg"/> <img alt="modern-errors 标志" src="https://yellow-cdn.veclightyear.com/835a84d5/909155bd-6d0c-4b60-b7be-0ebdd82184dd.svg" width="600"/> </picture>

Node 浏览器 TypeScript Codecov 压缩后大小 Mastodon Medium

以简单、稳定、一致的方式处理错误。

招聘我

如果您正在寻找一位 Node.js API 或 CLI 工程师(具有11年经验),请联系我。我最近在 Netlify BuildNetlify Plugins 担任技术主管2.5年。我可以接受全职远程职位。

特性

简单的模式用于:

稳定性:

插件

示例

创建错误

import ModernError from 'modern-errors' export const BaseError = ModernError.subclass('BaseError') export const UnknownError = BaseError.subclass('UnknownError') export const InputError = BaseError.subclass('InputError') export const AuthError = BaseError.subclass('AuthError') export const DatabaseError = BaseError.subclass('DatabaseError')

设置错误属性

throw new InputError('无效的文件路径', { props: { filePath: '/...' } })

包装错误。

try { // ... } catch (cause) { throw new InputError('无法读取文件。', { cause }) }

规范化错误。

try { throw '缺少文件路径。' } catch (error) { // 从字符串规范化为 `BaseError` 实例 throw BaseError.normalize(error) }

使用插件

import ModernError from 'modern-errors' import modernErrorsSerialize from 'modern-errors-serialize' export const BaseError = ModernError.subclass('BaseError', { plugins: [modernErrorsSerialize], }) // ... // 将错误序列化为 JSON,然后再解析回相同的错误实例 const error = new InputError('缺少文件路径。') const errorString = JSON.stringify(error) const identicalError = BaseError.parse(JSON.parse(errorString))

安装

npm install modern-errors

如果使用任何插件,也必须安装它们。

npm install modern-errors-{插件名}

这个包同时适用于 Node.js >=18.18.0 和浏览器

这是一个 ES 模块。它必须使用 import 或 import() 语句加载,而不是 require()。如果使用 TypeScript,必须将其配置为输出 ES 模块,而不是 CommonJS。

使用方法

⛑️ 错误类

创建错误类

import ModernError from 'modern-errors' export const BaseError = ModernError.subclass('BaseError') export const UnknownError = BaseError.subclass('UnknownError') export const InputError = BaseError.subclass('InputError') export const AuthError = BaseError.subclass('AuthError') export const DatabaseError = BaseError.subclass('DatabaseError')

导出错误类

导出并记录所有错误类允许使用者对其进行检查。这也使得在模块之间共享错误类成为可能。

检查错误类

if (error instanceof InputError) { // ... }

错误子类

ErrorClass.subclass()返回一个子类。 父类的选项与其子类的选项合并。

export const BaseError = ModernError.subclass('BaseError', { props: { isError: true }, }) export const InputError = BaseError.subclass('InputError', { props: { isUserError: true }, }) const error = new InputError('...') console.log(error.isError) // true console.log(error.isUserError) // true console.log(error instanceof BaseError) // true console.log(error instanceof InputError) // true

🏷️ 错误属性

错误类属性

const InputError = BaseError.subclass('InputError', { props: { isUserError: true }, }) const error = new InputError('...') console.log(error.isUserError) // true

错误实例属性

const error = new InputError('...', { props: { isUserError: true } }) console.log(error.isUserError) // true

内部错误属性

内部或秘密的错误属性可以用_作为前缀。这使它们成为不可枚举的,从而防止被迭代或记录。

const error = new InputError('...', { props: { userId: 6, _isUserError: true }, }) console.log(error.userId) // 6 console.log(error._isUserError) // true console.log(Object.keys(error)) // ['userId'] console.log(error) // 记录`userId`,但不记录`_isUserError`

🎀 包装错误

抛出错误

throw new InputError('缺少文件路径。')

包装内部错误

任何错误的消息选项都可以使用标准cause选项进行包装。

内部错误不会被设置为cause属性,而是直接合并到外部错误中,包括其messagestacknameAggregateError.errors和任何附加属性

try { // ... } catch (cause) { throw new InputError('无法读取文件。', { cause }) }

包装错误消息

外部错误消息会被追加,除非它为空。如果外部错误消息以::\n结尾,则会被前置。

const cause = new InputError('文件不存在。') // InputError: 文件不存在。 throw new InputError('', { cause })
// InputError: 文件不存在。 // 无法读取文件。 throw new InputError('无法读取文件。', { cause })
// InputError: 无法读取文件:文件不存在。 throw new InputError(`无法读取文件:`, { cause })
// InputError: 无法读取文件: // 文件不存在。 throw new InputError(`无法读取文件:\n`, { cause })

包装错误类

外部错误的类会替换内部错误的类。

try { throw new AuthError('...') } catch (cause) { // 现在是InputError throw new InputError('...', { cause }) }

除非外部错误的类是父类,比如BaseError

try { throw new AuthError('...') } catch (cause) { // 仍然是AuthError throw new BaseError('...', { cause }) }

包装错误选项

外部错误的props插件选项会被合并。

try { throw new AuthError('...', innerOptions) } catch (cause) { // `outerOptions`与`innerOptions`合并 throw new BaseError('...', { ...outerOptions, cause }) }

聚合错误

errors选项将多个错误聚合成一个。这类似于new AggregateError(errors),但适用于任何错误类。

const databaseError = new DatabaseError('...') const authError = new AuthError('...') throw new InputError('...', { errors: [databaseError, authError] }) // InputError: ... { // [errors]: [ // DatabaseError: ... // AuthError: ... // ] // }

🚨 规范化错误

包装的错误

任何错误都可以直接传递给causeerrors选项,即使它是无效的未知的或未规范化的

try { // ... } catch (cause) { throw new InputError('...', { cause }) }

无效错误

操作不是Error实例或具有无效属性的错误可能导致意外的错误。 BaseError.normalize()可以解决这个问题。

try { throw '缺少文件路径。' } catch (invalidError) { // 这会失败:`invalidError.message`是`undefined` console.log(invalidError.message.trim()) }
try { throw '缺少文件路径。' } catch (invalidError) { const normalizedError = BaseError.normalize(invalidError) // 这样可以正常工作: '缺少文件路径。' // `normalizedError` 是 `BaseError` 的实例。 console.log(normalizedError.message.trim()) }

🐞 未知错误

处理已知错误

已知错误应该在 try {} catch {} 块中处理,并用特定类包装。该块应该只覆盖可能抛出错误的语句,以防止捕获其他不相关的错误。

try { return regExp.test(value) } catch (error) { // 现在是 `InputError` 实例 throw new InputError('无效的正则表达式:', { cause: error }) }

标准化未知错误

如果错误没有按照上述方式处理,就被视为_未知_。这表示发生了意外异常,通常是一个bug。 BaseError.normalize(error, UnknownError)UnknownError 类分配给这些错误。

export const UnknownError = BaseError.subclass('UnknownError')
try { return regExp.test(value) } catch (error) { // 现在是 `UnknownError` 实例 throw BaseError.normalize(error, UnknownError) }

顶级错误处理器

BaseError.normalize(error, UnknownError)包装模块的主要函数可以确保每个抛出的错误都是有效的,应用了插件,并且具有已知UnknownError类。

export const main = () => { try { // ... } catch (error) { throw BaseError.normalize(error, UnknownError) } }

🔌 插件

插件列表

插件扩展了 modern-errors 的功能。所有可用的插件都列在这里

添加插件

要使用插件,请先安装它,然后将其传递给plugins 选项

npm install modern-errors-{pluginName}
import ModernError from 'modern-errors' import modernErrorsBugs from 'modern-errors-bugs' import modernErrorsSerialize from 'modern-errors-serialize' export const BaseError = ModernError.subclass('BaseError', { plugins: [modernErrorsBugs, modernErrorsSerialize], }) // ...

自定义插件

请查看以下文档以创建你自己的插件。

插件选项

大多数插件可以通过选项进行配置。选项的名称与插件相同。

const options = { // `modern-errors-bugs` 选项 bugs: 'https://github.com/my-name/my-project/issues', // `props` 可以像插件选项一样配置和修改 props: { userId: 5 }, }

插件选项可以应用于(按优先顺序):

export const BaseError = ModernError.subclass('BaseError', options)
export const InputError = BaseError.subclass('InputError', options)
throw new InputError('...', options)
  • 插件方法调用: 最后一个参数,仅传递该插件的选项
ErrorClass[methodName](...args, options[pluginName])
error[methodName](...args, options[pluginName])

🔧 自定义逻辑

custom 选项可用于为错误提供额外的方法、constructor、属性或选项。

export const InputError = BaseError.subclass('InputError', { // `class` 必须继承自父错误类 custom: class extends BaseError { // 如果定义了 `constructor`,其参数必须是 (message, options) // 可以定义额外的 `options`。 constructor(message, options) { message += options?.suffix ?? '' super(message, options) } isUserInput() { // ... } }, }) const error = new InputError('错误的用户名', { suffix: ': 示例' }) console.log(error.message) // '错误的用户名: 示例' console.log(error.isUserInput())

🤓 TypeScript

请查看以下文档了解有关 TypeScript 类型的信息。

API

ModernError

顶级 ErrorClass

ErrorClass.subclass(name, options?)

name: string
options: ClassOptions?

创建并返回一个子 ErrorClass

options

options.props

类型: object

错误类属性

options.plugins

类型: Plugin[]

options.custom

类型: class extends ErrorClass {}

自定义类,用于添加任何方法、constructor 或属性。

options.*

任何插件选项也可以在此指定。

new ErrorClass(message, options?)

message: string
options: InstanceOptions?
返回值: Error

options

options.props

类型: object

错误实例属性

options.cause

类型: any

包装的内部错误。

options.errors

类型: any[]

聚合的错误数组。

options.*

任何插件选项也可以在此指定。

ErrorClass.normalize(error, NewErrorClass?)

error: Error | any
NewErrorClass: ErrorClass 的子类
返回值: Error

标准化无效错误

如果 error 的类是 ErrorClass 的子类,它将保持不变。 否则,它将被转换为 NewErrorClass,默认为 ErrorClass 本身。

模块

这个框架汇集了一系列可以单独使用的模块:

支持

如有任何问题,请_不要犹豫_在 GitHub 上提交问题

我们欢迎所有人,不论个人背景如何。我们执行行为准则以促进积极和包容的环境。

贡献

这个项目是用 ❤️ 制作的。回馈的最简单方式是给它加星并在网上分享。

如果文档不清楚或有错别字,请点击页面的编辑按钮(铅笔图标)并提出修改建议。

如果您想帮助我们修复错误或添加新功能,请查看我们的指南。欢迎提交拉取请求!

<!-- 感谢我们出色的贡献者: --> <!-- ALL-CONTRIBUTORS-LIST:START --> <!-- prettier-ignore-start --> <!-- markdownlint-disable --> <table> <tbody> <tr> <td align="center" valign="top" width="14.28%"><a href="https://fosstodon.org/@ehmicky"><img src="https://avatars2.githubusercontent.com/u/8136211?v=4?s=100" width="100px;" alt="ehmicky"/><br /><sub><b>ehmicky</b></sub></a><br /><a href="https://github.com/ehmicky/modern-errors/commits?author=ehmicky" title="代码">💻</a> <a href="#design-ehmicky" title="设计">🎨</a> <a href="#ideas-ehmicky" title="想法、规划与反馈">🤔</a> <a href="https://github.com/ehmicky/modern-errors/commits?author=ehmicky" title="文档">📖</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/bhvngt"><img src="https://avatars.githubusercontent.com/u/79074469?v=4?s=100" width="100px;" alt="const_var"/><br /><sub><b>const_var</b></sub></a><br /><a href="#ideas-bhvngt" title="想法、规划与反馈">🤔</a> <a href="#question-bhvngt" title="回答问题">💬</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/abrenneke"><img src="https://avatars.githubusercontent.com/u/342540?v=4?s=100" width="100px;" alt="Andy Brenneke"/><br /><sub><b>Andy Brenneke</b></sub></a><br /><a href="#ideas-abrenneke" title="想法、规划与反馈">🤔</a> <a href="#question-abrenneke" title="回答问题">💬</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/tgfisher4"><img src="https://avatars.githubusercontent.com/u/49082176?v=4?s=100" width="100px;" alt="Graham Fisher"/><br /><sub><b>Graham Fisher</b></sub></a><br /><a href="https://github.com/ehmicky/modern-errors/issues?q=author%3Atgfisher4" title="错误报告">🐛</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/renzor-fist"><img src="https://avatars.githubusercontent.com/u/117486829?v=4?s=100" width="100px;" alt="renzor"/><br /><sub><b>renzor</b></sub></a><br /><a href="#question-renzor-fist" title="回答问题">💬</a> <a href="#ideas-renzor-fist" title="想法、规划与反馈">🤔</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/eugene1g"><img src="https://avatars.githubusercontent.com/u/147496?v=4?s=100" width="100px;" alt="Eugene"/><br /><sub><b>Eugene</b></sub></a><br /><a href="https://github.com/ehmicky/modern-errors/commits?author=eugene1g" title="代码">💻</a> <a href="https://github.com/ehmicky/modern-errors/issues?q=author%3Aeugene1g" title="错误报告">🐛</a></td> <td align="center" valign="top" width="14.28%"><a href="http://uk.linkedin.com/in/jonathanmarkchambers/"><img src="https://avatars.githubusercontent.com/u/49592?v=4?s=100" width="100px;" alt="Jonathan Chambers"/><br /><sub><b>Jonathan Chambers</b></sub></a><br /><a href="https://github.com/ehmicky/modern-errors/commits?author=jmchambers" title="测试">⚠️</a> <a href="https://github.com/ehmicky/modern-errors/issues?q=author%3Ajmchambers" title="错误报告">🐛</a></td> </tr> </tbody> </table> <!-- markdownlint-restore --> <!-- prettier-ignore-end --> <!-- ALL-CONTRIBUTORS-LIST:END -->

编辑推荐精选

TRAE编程

TRAE编程

AI辅助编程,代码自动修复

Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。

AI工具TraeAI IDE协作生产力转型热门
商汤小浣熊

商汤小浣熊

最强AI数据分析助手

小浣熊家族Raccoon,您的AI智能助手,致力于通过先进的人工智能技术,为用户提供高效、便捷的智能服务。无论是日常咨询还是专业问题解答,小浣熊都能以快速、准确的响应满足您的需求,让您的生活更加智能便捷。

imini AI

imini AI

像人一样思考的AI智能体

imini 是一款超级AI智能体,能根据人类指令,自主思考、自主完成、并且交付结果的AI智能体。

Keevx

Keevx

AI数字人视频创作平台

Keevx 一款开箱即用的AI数字人视频创作平台,广泛适用于电商广告、企业培训与社媒宣传,让全球企业与个人创作者无需拍摄剪辑,就能快速生成多语言、高质量的专业视频。

即梦AI

即梦AI

一站式AI创作平台

提供 AI 驱动的图片、视频生成及数字人等功能,助力创意创作

扣子-AI办公

扣子-AI办公

AI办公助手,复杂任务高效处理

AI办公助手,复杂任务高效处理。办公效率低?扣子空间AI助手支持播客生成、PPT制作、网页开发及报告写作,覆盖科研、商业、舆情等领域的专家Agent 7x24小时响应,生活工作无缝切换,提升50%效率!

蛙蛙写作

蛙蛙写作

AI小说写作助手,一站式润色、改写、扩写

蛙蛙写作—国内先进的AI写作平台,涵盖小说、学术、社交媒体等多场景。提供续写、改写、润色等功能,助力创作者高效优化写作流程。界面简洁,功能全面,适合各类写作者提升内容品质和工作效率。

AI辅助写作AI工具蛙蛙写作AI写作工具学术助手办公助手营销助手AI助手
问小白

问小白

全能AI智能助手,随时解答生活与工作的多样问题

问小白,由元石科技研发的AI智能助手,快速准确地解答各种生活和工作问题,包括但不限于搜索、规划和社交互动,帮助用户在日常生活中提高效率,轻松管理个人事务。

热门AI助手AI对话AI工具聊天机器人
Transly

Transly

实时语音翻译/同声传译工具

Transly是一个多场景的AI大语言模型驱动的同声传译、专业翻译助手,它拥有超精准的音频识别翻译能力,几乎零延迟的使用体验和支持多国语言可以让你带它走遍全球,无论你是留学生、商务人士、韩剧美剧爱好者,还是出国游玩、多国会议、跨国追星等等,都可以满足你所有需要同传的场景需求,线上线下通用,扫除语言障碍,让全世界的语言交流不再有国界。

讯飞智文

讯飞智文

一键生成PPT和Word,让学习生活更轻松

讯飞智文是一个利用 AI 技术的项目,能够帮助用户生成 PPT 以及各类文档。无论是商业领域的市场分析报告、年度目标制定,还是学生群体的职业生涯规划、实习避坑指南,亦或是活动策划、旅游攻略等内容,它都能提供支持,帮助用户精准表达,轻松呈现各种信息。

AI办公办公工具AI工具讯飞智文AI在线生成PPTAI撰写助手多语种文档生成AI自动配图热门
下拉加载更多