关于 neverthrow-wrap-exceptions
neverthrow-wrap-exceptions 是面向编码的技能,用于将可恢复的同步和异步异常转换为带类型的 neverthrow 结果,并指导开发者选择包装方法、显式映射错误。
主要功能
- 01按失败类型选择包装方法
- 02将错误映射为明确类型
- 03组合现有 Result 值
- 04替换仅用于转换的 catch 链
- 05检查异常处理变更
适用场景
- 01包装可能抛出异常的同步解析器
- 02将拒绝的 Promise 转换为领域错误
- 03重构基于 catch 的临时转换
- 04审查代码中的错误处理
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ code-sherpas/ agent-skills --skill neverthrow-wrap-exceptions安装后在 Claude Code 中输入/neverthrow-wrap-exceptions确认已加载。
详细介绍
neverthrow 异常封装
目标
使用 neverthrow 辅助函数捕获可恢复的异常,而不是随意使用 try/catch。
此技能仅适用于异常捕获。如果任务还会更改公开的返回签名,请同时使用 neverthrow-return-types。
检测异常来源
-
找出失败当前从何处进入代码。
- 查找手写的
try/catch、仅用于转换的.catch(...)封装、已知会抛出异常的 API 的直接调用,以及可能拒绝的返回 Promise 的函数。 - 检查第三方库、解析器、数据库客户端、网络客户端、文件系统辅助函数、架构验证器和序列化代码。
- 查找手写的
-
在选择封装函数前,区分失败形态。
- 如果操作可能在返回值之前抛出异常,则使用同步路径。
- 如果操作返回 Promise,但在该 Promise 创建之前仍可能抛出异常,则使用 Promise 函数路径。
- 如果手头已经有
PromiseLike值,则使用 Promise 实例路径。
-
不要封装已经返回
Result或ResultAsync的 API。- 直接使用
map、mapErr、andThen、asyncAndThen或orElse组合。
- 直接使用
选择封装函数
-
对于会抛出异常的同步函数,使用
Result.fromThrowable或fromThrowable。- 始终传入错误映射函数,以便
Err一侧具有明确的类型。
- 始终传入错误映射函数,以便
-
对于可能在返回前抛出异常或在异步执行期间失败的返回 Promise 的函数,使用
ResultAsync.fromThrowable。- 如果函数调用本身可能抛出异常,优先使用此方法,而不是
ResultAsync.fromPromise(fn(...), ...)。
- 如果函数调用本身可能抛出异常,优先使用此方法,而不是
-
如果手头已经有
PromiseLike值,则使用ResultAsync.fromPromise或fromPromise。- 立即将拒绝值映射为具体的错误类型。
-
当同一种错误形态反复出现时,复用范围明确的映射函数。
- 优先使用稳定的领域错误,而不是
unknown、any和泛化字符串。
- 优先使用稳定的领域错误,而不是
默认避免 try/catch
-
如果
neverthrow辅助函数适用,不要新增手写的try/catch块。- 如有需要,将存在风险的操作提取为函数,再封装该函数。
-
只有当周围的结构确实需要时才保留
try/catch。- 例如需要
finally的清理流程、必须拦截并转换异常的框架边界,或者无法仅通过封装辅助函数清晰表达的语言结构。
- 例如需要
-
如果必须保留
try/catch,应将其置于范围最窄的边界。- 立即将捕获的值转换为
Err或所需的框架原生响应。 - 不要让捕获的值以未类型化的
unknown在代码库中流转。
- 立即将捕获的值转换为
实现规则
-
在可能抛出异常或拒绝的操作源头附近封装一次。
- 避免对同一操作进行嵌套封装。
-
明确进行错误映射。
- 如果符合本地代码风格,优先使用能保留有用上下文的映射函数,例如操作名称、输入标识符或上游状态码。
-
当
neverthrow提供了更清晰的封装方式时,替换仅用于转换的.catch(...)链。- 不要使用
Promise.resolve、Promise.reject或自定义封装对象手动模拟ResultAsync。
- 不要使用
示例模式
const parseConfig = Result.fromThrowable(
JSON.parse,
(error) => ({ type: 'ConfigParseError', cause: error }),
)
const fetchUser = ResultAsync.fromThrowable(
apiClient.getUser,
(error) => ({ type: 'UserFetchError', cause: error }),
)
function readBody(): ResultAsync<RequestBody, BodyReadError> {
return ResultAsync.fromPromise(request.json(), toBodyReadError)
}
完成前验证
- 确认新增或修改的失败捕获在适用时使用了
neverthrow辅助函数。 - 确认每种封装函数的选择都符合实际失败形态:同步抛出异常、返回 Promise 的函数,或现有 Promise。
- 确认所有错误映射函数都生成了明确的错误类型。
- 确认任何保留的
try/catch块都有实际约束作为理由,而非仅仅沿袭习惯。 - 在安全且任务范围允许的情况下,运行当前技术栈的常规本地验证,例如测试、代码检查或类型检查。
报告结果
完成任务时:
- 说明包装了哪些会抛出异常或拒绝的操作。
- 说明使用了哪个
neverthrow辅助函数,以及原因。 - 说明还保留了哪些
try/catch代码块,以及它们为何不可避免。 - 说明如何将捕获或拒绝的值映射为显式错误类型。
评论
支持 Markdown