如何在fp-ts中结合Either与异步函数使用?
关于fp-ts异步流程优化的解答
首先,你的写法能正确运行,但不算fp-ts里最地道的函数式风格——手动用E.isLeft做分支判断,打破了链式调用的流畅性,而且直接await异步函数没有借助fp-ts的异步容器管理,丢失了函数式编程的组合优势。
要实现单个pipe完成全部逻辑,需要用到TaskEither(通常缩写为TE)——它是Either的异步版本,专门用来封装“可能失败的异步操作”,完美适配你的场景。
优化后的代码示例
import * as E from 'fp-ts/Either' import * as TE from 'fp-ts/TaskEither' import { pipe } from 'fp-ts/function' // 假设 getItem 类型为: (id: Item["id"]) => Promise<Item | null> const fetchItem = pipe( // 1. 从请求体获取itemId,转成Either(处理null/undefined情况) body.itemId, E.fromNullable('Item ID is missed'), // 2. 将Either转为TaskEither,进入异步流程上下文 TE.fromEither, // 3. 链式调用异步函数,同时处理"获取不到item"的情况 TE.chain(itemId => TE.chainNullableK(() => getItem(itemId))('cant find item') ) ) // 执行TaskEither,得到最终的Either结果 const item: E.Either<string, Item> = await fetchItem()
代码说明
TE.fromEither: 把同步的Either转为异步的TaskEither,让后续能链式调用异步操作。TE.chainNullableK: 这是fp-ts提供的组合子,专门用来处理“返回值可能为null/undefined的异步函数”——它会自动把null转为指定的错误信息(这里是'cant find item'),省去手动判断null的步骤。
如果你不想用chainNullableK,也可以手动用TE.fromPromise + TE.fromEither组合实现:
const fetchItem = pipe( body.itemId, E.fromNullable('Item ID is missed'), TE.fromEither, TE.chain(itemId => pipe( getItem(itemId), TE.fromPromise, // 把Promise转为TaskEither,捕获异步调用的异常 TE.chain(item => TE.fromEither(E.fromNullable('cant find item')(item))) ) ) )
这种写法全程用pipe串联逻辑,没有命令式的分支判断,完全符合fp-ts的函数式编程理念,同时还能自动处理异步调用的异常(如果getItem抛出错误,TE.fromPromise会把错误转为Left)。
内容的提问来源于stack exchange,提问作者Petr Tcoi
相关产品推荐
相关产品推荐

