You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在fp-ts中让TaskEither忽略单个错误返回成功结果?

问题

我正在使用fp-ts库,需要并行调用两个可能失败的函数first和second,它们的返回类型都是TE.TaskEither<Error, User>。

当前我用TE.sequenceArray([first, second])调用,它的返回类型是TE.TaskEither<Error, ReadonlyArray<User>>,但这个方法是"快速失败"的——只要其中一个调用失败,整个结果就会直接返回Left,不符合我的需求。

我需要实现的逻辑是:

  • 若两个调用都失败(无用户找到),返回Left(Error("user does not exist"))
  • 只要有一个调用成功,就返回Right(ReadonlyArray<User>)(包含1个或2个User)
  • 其他异常情况返回Left(Error("internal server error"))

我尝试过以下代码,但发现if判断逻辑根本没执行:

F.pipe(
  TE.sequenceArray([first, second]),
  TE.chain(successes => {
     if (successes.length > 0) {
        return TE.right(successes);
    } else {
      return TE.left(Error());
    }
  }),
  TE.map(results => results.flat()),
);

解决方案

核心问题分析

TE.sequenceArray的特性是快速失败:只要数组中有任意一个TaskEither返回Left,整个sequenceArray就会直接返回Left,不会进入后续的TE.chain逻辑,这就是你的if判断没执行的原因。

要实现"允许单个失败,只在全失败时返回错误"的逻辑,需要先把每个任务的失败结果转换成成功容器内的"空值",再统一处理结果。

具体实现步骤

  1. 转换单个任务的错误处理:把每个TaskEither<Error, User>转换成TaskEither<Error, Option<User>>——成功时返回Right(Some(user)),失败时返回Right(None)(这里只捕获"用户不存在"的错误,其他异常仍保留为Left)。
  2. 并行执行所有任务:用TE.sequenceArray执行转换后的任务数组,得到所有结果的集合。
  3. 过滤有效结果并判断:从结果数组中提取出所有Some(User)的项,再根据数量返回对应结果。

代码示例

import * as TE from 'fp-ts/TaskEither';
import * as O from 'fp-ts/Option';
import * as F from 'fp-ts/function';
import { filter } from 'fp-ts/ReadonlyArray';

// 假设User类型已定义
type User = { id: string; name: string };

// 转换单个任务:将失败(用户不存在)转为None,其他异常保留为Left
const toOptionTask = (te: TE.TaskEither<Error, User>) =>
  TE.fold(
    (err) => {
      // 假设"用户不存在"的错误可以通过err.message判断,根据实际情况调整
      if (err.message.includes('user does not exist')) {
        return TE.right(O.none);
      }
      // 其他异常仍返回Left
      return TE.left(new Error('internal server error'));
    },
    (user) => TE.right(O.some(user))
  )(te);

// 主逻辑
const getUsers = F.pipe(
  // 转换两个任务
  [toOptionTask(first), toOptionTask(second)],
  TE.sequenceArray,
  TE.chain((results) => {
    // 过滤出存在的User
    const validUsers = filter(O.isSome)(results).map(O.getOrElse(() => undefined as User));
    if (validUsers.length === 0) {
      return TE.left(new Error('user does not exist'));
    }
    return TE.right(validUsers);
  })
);

代码说明

  • toOptionTask函数:将任务的失败分为两种情况——"用户不存在"转为Right(None),其他异常直接返回Left,保证只有预期的失败会被纳入结果集合。
  • TE.sequenceArray:此时因为每个任务的失败(用户不存在)都被转为Right(None),所以不管单个任务是否成功,sequenceArray都会返回Right(ReadonlyArray<Option<User>>),确保后续逻辑能执行。
  • 过滤与判断:从结果数组中提取有效User,空数组则返回"用户不存在"错误,否则返回有效User数组。

内容的提问来源于stack exchange,提问作者needith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 16:43:10