使用fp-ts时如何从TaskEither数组中收集Left值?
如何收集TaskEither数组中的所有Left值(避免短路)
我有一个向订阅者广播事件的函数,返回结果为TaskEither<Error, void>[]。之前一直用sequenceArray将其转换为TaskEither<Error, void[]>,但现在希望收集所有Left值(错误),而不是关注Right值。尝试过swap(sequenceArray(results.map(swap))),但这个方法不奏效——因为sequenceArray遇到Left就会短路,最终出错时只能得到void,无法收集所有错误。
解决方案:逐个执行并汇总错误
要实现不短路的错误收集,需要先把每个TaskEither转换为普通Task(确保所有任务都执行),再过滤汇总错误:
- 转换TaskEither为Task
用fold将每个TaskEither<Error, void>转为Task<Error | undefined>,Left返回错误,Right返回undefined标记无错误:
import { TaskEither, fold } from 'fp-ts/TaskEither'; import { Task, of } from 'fp-ts/Task'; const toErrorTask = (te: TaskEither<Error, void>): Task<Error | undefined> => fold( (err) => of(err), () => of(undefined) )(te);
- 执行所有Task并收集结果
用sequenceArray执行所有转换后的Task,这一步不会短路:
import { sequenceArray } from 'fp-ts/Array'; const taskArray = results.map(toErrorTask); const rawResults = sequenceArray(taskArray); // Task<(Error | undefined)[]>
- 过滤出错误数组
过滤掉undefined,得到仅包含错误的数组:
import { map } from 'fp-ts/Task'; import { filter } from 'fp-ts/Array'; import { isDefined } from 'fp-ts/Option'; const collectedErrors = map(filter(isDefined))(rawResults); // Task<Error[]>
- (可选)转为TaskEither
如果需要把错误数组放到TaskEither的Right中:
import { right } from 'fp-ts/TaskEither'; import { chain } from 'fp-ts/Task'; const errorsTE = chain((errs) => right(errs))(collectedErrors); // TaskEither<never, Error[]>
原方法失效的原因
sequenceArray是短路式的:只要数组中有一个TaskEither是Left,整个结果会直接返回该Left,不会执行后续任务。而上述方法通过先转换为普通Task,确保所有任务都被执行,再汇总错误,完美解决了短路问题。
内容的提问来源于stack exchange,提问作者Adam A
相关产品推荐
相关产品推荐

