Skip to content

TypeScript 异步编程:用 TaskEither 摆脱 try/catch 地狱

解决异步操作中常见的“try/catch 嵌套地狱”和错误上下文丢失问题,通过 TaskEither 将异步成功与失败显式化,构建可组合的纯净代码管道。

为什么需要这个技能

在 TypeScript 中,处理异步 API 调用通常依赖 async/awaittry/catch。当业务逻辑涉及多个依赖步骤时,代码会迅速陷入深层嵌套,且在 catch 块中很难精准追踪是哪个环节发生了错误。

TaskEither 的核心思想是将“异步操作”和“可能失败”这两个概念统一。它不再是简单的 Promise,而是一个在运行后会返回 Either(左侧是错误,右侧是成功值)的异步任务。这种方式将错误处理从命令式地“拦截”转变为声明式地“流转”,极大地提升了代码的可维护性和类型安全性。

适用场景

  • 需要在 TypeScript 中处理复杂的异步链路(如:请求 A 基于 A 请求 B 保存 C)。
  • 想要消除代码中大量重复的 if (!response.ok) 校验和嵌套 try/catch
  • 需要实现更高级的错误恢复机制,如特定错误回退、指数退避重试。
  • 追求强类型错误定义,确保所有可能的失败路径在编译期被覆盖。

核心工作流

1. 安全封装 Promise

使用 TE.tryCatch 将可能抛出异常的 Promise 转换为 TaskEither。这样你只需在入口处定义一次错误转换逻辑,后续步骤无需再写 try/catch

typescript
const fetchJson = <T>(url: string): TE.TaskEither<Error, T> =>
  TE.tryCatch(
    async () => {
      const response = await fetch(url)
      if (!response.ok) throw new Error(`HTTP ${response.status}`)
      return response.json()
    },
    (error) => error instanceof Error ? error : new Error(String(error))
  )

2. 构建异步管道

使用 pipe 结合 chain(用于异步/可能失败的转换)和 map(用于同步/不会失败的转换)来扁平化逻辑。

  • chain: 当下一步操作仍然返回 TaskEither 时使用。
  • Do notation: 当后续步骤需要依赖前面多个步骤的结果时,使用 TE.DoTE.bind 避免深层闭包。
typescript
const processOrder = (orderId: string) =>
  pipe(
    TE.Do,
    TE.bind('order', () => fetchOrder(orderId)),
    TE.bind('user', ({ order }) => fetchUser(order.userId)),
    TE.bind('payment', ({ user, order }) => chargePayment(user, order.total)),
    TE.map(({ order, payment }) => ({ orderId: order.id, paymentId: payment.id }))
  )

3. 并行与恢复

  • 并行执行:使用 sequenceT(TE.ApplyPar) 同时发起多个独立请求,提升性能。
  • 错误恢复:使用 orElse 实现备选方案(Fallback),或使用 fold 将最终结果分发给成功和失败的处理函数。

下载和安装

下载 fp-async 中文版 Skill ZIP

解压后将目录放入你的 AI 工具 skills 文件夹,重启工具后即可使用。具体路径参考内附的 USAGE.zh.md

你可能还需要

暂无推荐