
本文详解如何使用 orElse 正确处理 TaskEither 中异步失败路径,实现左右两侧统一为 TaskEither 类型,避免嵌套结构,并支持后续链式调用。
本文详解如何使用 `orelse` 正确处理 `taskeither` 中异步失败路径,实现左右两侧统一为 `taskeither
在函数式编程实践中,TaskEither
你遇到的问题非常典型:
const result = pipe( input, TE.right, TE.chain(requestChatMessage), TE.map(success), // ✅ success: string → TE.TaskEither<Error, string> TE.mapLeft(fail) // ❌ fail: Error → TE.TaskEither<Error, Error> ); // 类型变为:TE.TaskEither<TE.TaskEither<Error, Error>, string> // 即 Left 侧未被“展开”,形成嵌套,无法继续链式调用
关键误区在于:mapLeft 仅对 Left 值做同步转换,它不会执行异步逻辑,也不会扁平化返回的 TaskEither。要让 Left 分支也执行异步操作并融入同一层级的 TaskEither 结构,必须使用 orElse —— 它是 TaskEither 的 chainLeft,语义为:“当当前值为 Left(e) 时,用 e 调用提供的函数,该函数应返回一个新的 TaskEither
✅ 正确做法如下:
import * as TE from 'fp-ts/TaskEither'; import { pipe } from 'fp-ts/function'; // 假设类型定义 type Input = string; type SuccessResult = string; type FailureResult = Error; // 异步成功处理器:string → Promise<string> const onRequestSuccess = (result: string): Promise<string> => Promise.resolve(`Processed: ${result}`); // 异步失败处理器:Error → Promise<Error> const onRequestFail = (error: Error): Promise<Error> => Promise.resolve(new Error(`Handled: ${error.message}`)); // 将异步函数安全包裹为 TaskEither const safeOnRequestSuccess = (result: string) => TE.tryCatch(() => onRequestSuccess(result), () => new Error('onRequestSuccess failed')); const safeOnRequestFail = (error: Error) => TE.tryCatch(() => onRequestFail(error), () => new Error('onRequestFail failed')); // 核心流程:使用 orElse 处理 Left 分支 const finalFlow = (input: Input) => pipe( input, TE.right, // 初始化为 Right(input) TE.chain(requestChatMessage), // 假设 requestChatMessage: string → TE.TaskEither<Error, string> TE.chain(safeOnRequestSuccess), // 成功后继续异步处理(Right 分支) TE.orElse(safeOnRequestFail) // ⚠️ 关键:当上一步为 Left(err) 时,用 err 调用 safeOnRequestFail ); // 最终类型为:() => Promise<Either<Error, string>> // 可无缝接入后续 chain/fold: const finalResult = pipe( finalFlow("hello"), TE.chain((data) => TE.right(`Final: ${data}`)), // 继续处理成功数据 TE.fold( (e) => console.error('Failed:', e.message), (a) => console.log('Success:', a) ) );
? 重要注意事项:
- orElse 的参数函数接收 Left 值(即错误),必须返回 TaskEither
,而非普通 Promise 或 Either ;否则类型不匹配。 - 若需统一左右两侧的错误类型(如都转为 AppError),可在 safeOnRequestFail 内完成转换,orElse 会自然继承其 Left 类型。
- 不要尝试用 flattenW 处理 Left —— flattenW 仅作用于 TaskEither
, A> 这类右嵌套结构,对左嵌套无效。 - orElse 是 chainLeft 的别名,语义清晰:它“重写”失败路径,使其产出与成功路径同构的 TaskEither。
✅ 总结:当你需要在 TaskEither 流程中对失败分支执行异步逻辑并保持类型扁平,orElse 是唯一正确且符合函数式语义的工具。它确保整个管道始终处于 TaskEither