mcpField
B
better-result-adopt

better-result-adopt

github.com/dmmulroy开发2.0k578 次安装9 周前更新
代码仓库

关于 better-result-adopt

better-result Adopt 是一项技能,用于在现有代码库中逐步引入 better-result。它指导开发者采用类型化错误处理并限定迁移范围,无需整体重写。

主要功能

  1. 01用 Result API 替换 try/catch
  2. 02将可空返回值改为 Result
  3. 03定义领域专用 TaggedError 类型
  4. 04使用 andThen 或 Result.gen 组合流程
  5. 05迁移时保留错误上下文

适用场景

  1. 01将 I/O 边界迁移到 Result
  2. 02替换模块中的 null 标记值
  3. 03统一服务中的错误类型
  4. 04重构嵌套错误处理

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dmmulroy/better-result --skill better-result-adopt

安装后在 Claude Code 中输入/better-result-adopt确认已加载。

附带文件references/tagged-errors.md

详细介绍

better-result 迁移

在现有代码库中逐步采用 better-result,无需一次性重写所有内容。

适用场景

当用户希望进行以下操作时,使用此技能:

  • 将 try/catch 迁移为 Result.try 或 Result.tryPromise
  • 将可空返回值替换为类型化的 Result<T, E>
  • 定义特定领域的 TaggedError 类型
  • 将嵌套错误处理重构为 andThen 链或 Result.gen
  • 在服务或模块中统一错误处理方式

阅读顺序

任务要阅读的文件
在模块中采用 better-result此文件
定义或审查错误类型references/tagged-errors.md
检查库的实现细节如存在,则检查 opensrc/

前置条件

编辑代码前:

  1. 确认目标项目已安装 better-result。
  2. 检查是否存在 opensrc/ 目录。如存在,阅读其中的包源代码,了解当前用法。
  3. 先确定迁移范围:一个文件、一个模块或一个边界层。

迁移策略

1. 从边界开始

从 I/O 边界和异常较多的代码入手:

  • HTTP 客户端
  • 数据库访问
  • 文件系统操作
  • 解析和验证
  • 框架适配器

不要一次性转换整个代码库。

2. 对现有失败进行分类
类别示例目标形式
领域错误未找到、验证、认证TaggedError + Result.err
基础设施错误网络、DB、文件 I/OResult.tryPromise + 映射后的错误
程序员缺陷错误假设、空值解引用保留抛出行为;在 Result 回调中,缺陷会变成 Panic
3. 按以下顺序迁移
  1. 定义错误类型。
  2. 使用 Result.try / Result.tryPromise 包装会抛出异常的边界。
  3. 将 null 或布尔哨兵返回值替换为 Result。
  4. 重构调用点,以传递 Result 值。
  5. 将嵌套分支收拢为 andThen、mapError 或 Result.gen。

核心转换

Try/catch → Result.try
function parseConfig(json: string): Result<Config, ParseError> {
  return Result.try({
    try: () => JSON.parse(json) as Config,
    catch: (cause) => new ParseError({ cause, message: `Parse failed: ${cause}` }),
  });
}
异步抛出 → Result.tryPromise
async function fetchUser(id: string): Promise<Result<User, ApiError | UnhandledException>> {
  return Result.tryPromise({
    try: async () => {
      const res = await fetch(`/api/users/${id}`);
      if (!res.ok) throw new ApiError({ status: res.status, message: `API ${res.status}` });
      return res.json() as Promise<User>;
    },
    catch: (cause) => (cause instanceof ApiError ? cause : new UnhandledException({ cause })),
  });
}
Null 哨兵 → Result
function findUser(id: string): Result<User, NotFoundError> {
  const user = users.find((candidate) => candidate.id === id);
  return user
    ? Result.ok(user)
    : Result.err(new NotFoundError({ id, message: `User ${id} not found` }));
}
嵌套流程 → Result.gen
async function processOrder(orderId: string): Promise<Result<OrderResult, OrderError>> {
  return Result.gen(async function* () {
    const order = yield* Result.await(fetchOrder(orderId));
    const validated = yield* validateOrder(order);
    const result = yield* Result.await(submitOrder(validated));
    return Result.ok(result);
  });
}

执行工作流

  1. 检查目标模块中的 try、catch、.catch(...)、throw、null、undefined 和基于状态标记的错误处理。
  2. 在更改控制流之前,先定义或更新 TaggedError 类。
  3. 优先转换边界函数,并将其签名改为 Result<T, E> 或 Promise<Result<T, E>>。
  4. 更新直接调用方,使其处理或传递新的 Result。
  5. 组合多个返回 Result 的步骤时,使用 Result.gen 或 andThen。
  6. 保留错误上下文,包括 cause、ID、消息和其他结构化字段。
  7. 运行测试,并为成功和错误路径添加覆盖。

完成标准

满足以下条件时,迁移即告完成:

  • 目标函数不再依赖 try/catch 处理预期的领域失败
  • 可空或哨兵错误返回值已替换为显式的 Result 值
  • 领域失败使用类型化的 TaggedError 类
  • 调用方会传递 Result,或显式对其进行解包或匹配
  • 测试至少覆盖一个成功路径和一个有代表性的错误路径

常见陷阱

  • 对所有内容都进行过度包装,而不是从边界开始
  • 映射错误时丢失原始失败上下文
  • 在同一流程的深处混用基于 throw 和基于 Result 的 API
  • 捕获 Panic,而不是修复底层缺陷

本参考文档

文件用途
references/tagged-errors.mdTaggedError 模式、匹配、类型守卫和示例

如果存在 opensrc/,请将其视为实现细节和当前 API 行为的准确信息来源。

评论

支持 Markdown