本技能介绍如何使用 fp-ts 库进行实用的错误处理,目标是摆脱到处使用 try/catch 的混乱写法,把错误当作数据来处理,让 TypeScript 能够追踪错误。
一、核心理念
异常在类型签名中是不可见的,会破坏函数之间的契约。例如一个声明返回 User 的函数,实际上可能抛出错误,调用者无从得知。本技能主张把错误作为值返回,让类型系统明确表达“这个操作可能失败”。
二、Either:同步结果模式
Either<E, A> 表示一个值要么是错误(Left),要么是成功值(Right)。创建方式为 E.right(42) 和 E.left('Oops')。可以用 E.isRight 判断,或用 E.fold 进行模式匹配。常用操作包括:E.map 转换成功值、E.mapLeft 转换错误、E.getOrElse 提供默认值、E.fromNullable 把可空值转为 Either。对于会抛异常的代码,用 E.tryCatch 包装,可复用的场景用 E.tryCatchK。
三、串联可能失败的操作
用 E.chain 把多个返回 Either 的函数串联成管道,第一个错误会中断后续步骤。当各步骤错误类型不同时,用 E.chainW(W 表示 wider)自动合并错误类型。还可以用 E.filterOrElse 对成功值加条件过滤。E.Do 配合 E.bind 的写法可以更清晰地访问中间值。
四、收集多个错误
表单校验等场景需要收集全部错误而非只返回第一个。做法是用 E.getApplicativeValidation 配合 NEA.getSemigroup 构造可累积错误的 applicative,再用 sequenceS 组合多个校验器。错误类型可以是字符串数组,也可以是带字段名的对象数组,便于在 UI 中按字段显示。
五、TaskEither:异步操作
TaskEither<E, A> 本质是返回 Promise<Either<E, A>> 的函数,且是惰性的,不执行就不运行。用 TE.tryCatch 包装异步操作,用 TE.chain 串联,用 sequenceS(TE.ApplyPar) 并行执行多个异步任务。执行时调用返回的函数得到 Promise。可以用 TE.fold 处理成功与失败两种情况。教程还给出了重试(带指数退避)和降级(先缓存后 API 再默认值)的实现示例。
六、模式之间的转换
教程说明了如何在可空值、Option、会抛异常的函数、Promise 与 Either/TaskEither 之间转换。例如用 E.fromNullable 处理可空值,用 E.fromOption 从 Option 转换,用 TE.tryCatch 包装 fetch、axios、prisma 等异步库。需要回到普通 Promise 时,可以取回 Either、在错误时 reject,或在错误时使用默认值。
七、实际场景
教程给出了两个完整示例:一是安全解析用户输入,用 E.Do 和 E.bind 逐步校验对象结构、字段类型;二是带完整错误处理的 API 调用,定义包含 code、message、status 的 ApiError 结构。
八、适用场景与限制
适用于 TypeScript 项目中希望以类型安全、可预测方式处理同步与异步错误的开发者,尤其是表单校验、API 调用链、需要重试或降级的场景。限制方面:资料未提供关于性能、学习曲线、与其他库对比、版本要求或平台限制的说明。