Appearance
TypeScript 异步编程:用 TaskEither 摆脱 try/catch 地狱
解决异步操作中常见的“try/catch 嵌套地狱”和错误上下文丢失问题,通过 TaskEither 将异步成功与失败显式化,构建可组合的纯净代码管道。
为什么需要这个技能
在 TypeScript 中,处理异步 API 调用通常依赖 async/await 和 try/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.Do和TE.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将最终结果分发给成功和失败的处理函数。
下载和安装
解压后将目录放入你的 AI 工具 skills 文件夹,重启工具后即可使用。具体路径参考内附的 USAGE.zh.md。
你可能还需要
暂无推荐