TypeScript函数式编程清洁架构项目错误排查求助
TypeScript函数式编程(fp-ts)两类类型错误修复方案
错误1:TaskEither<Error, void>无法赋值给TaskEither<Error, Option<User[]>>
原因分析
void类型通常来自以下场景:
- 在
TaskEither链式调用中使用map/chain时,内部函数未返回预期的Option<User[]>类型(比如函数无返回值、返回undefined)。 - 调用了返回
Promise<void>的异步函数,且未在链式操作中正确返回目标类型的结果。
修复示例
假设错误代码如下:
import { TaskEither, chain } from 'fp-ts/TaskEither'; import { Option } from 'fp-ts/Option'; type User = { id: number }; const saveAuditLog = async (): Promise<void> => { /* 记录日志的异步操作 */ }; // 错误写法:chain内部未返回正确的TaskEither类型 const fetchUsers: () => TaskEither<Error, Option<User[]>> = () => { return pipe( TaskEither.right(Option.some([{ id: 1 }])), chain(async (users) => { await saveAuditLog(); // 此处未返回users,导致返回Promise<void>,最终类型变为TaskEither<Error, void> }) ); };
修复后代码:
const fetchUsers: () => TaskEither<Error, Option<User[]>> = () => { return pipe( TaskEither.right(Option.some([{ id: 1 }])), chain(async (users) => { await saveAuditLog(); // 必须返回正确的TaskEither<Error, Option<User[]>>类型 return TaskEither.right(users); }) ); };
如果是误用map导致的无返回值:
// 错误写法:map内部无返回值 const fetchUsers = pipe( TaskEither.right(Option.some([{ id: 1 }])), map(() => console.log('Fetched users')) // 返回void,类型变为TaskEither<Error, void> ); // 修复:返回原Option<User[]> const fetchUsers = pipe( TaskEither.right(Option.some([{ id: 1 }])), map((users) => { console.log('Fetched users'); return users; }) );
错误2:(country: string) => TaskEither<Error, Option<User[]>>与(b: Either<DomainError, string>) => TaskEither<Error, Option<User[]>>不兼容
原因分析
Either是fp-ts库的核心类型,代表“要么成功值、要么错误值”的容器。错误根源是:链式调用(比如chain)中前一个TaskEither的右值是Either<DomainError, string>,但传入的函数只接受原始string类型,参数类型不匹配。
修复示例
假设错误代码如下:
import { TaskEither, chain } from 'fp-ts/TaskEither'; import { Either, right } from 'fp-ts/Either'; import { Option } from 'fp-ts/Option'; type DomainError = { type: 'InvalidCountry' }; type User = { id: number; country: string }; const fetchUsersByCountry = (country: string): TaskEither<Error, Option<User[]>> => { return TaskEither.right(Option.some([{ id: 1, country }])); }; // 错误写法:chain期望函数参数是Either<DomainError, string>,但fetchUsersByCountry只接受string const getUsers = () => { const validatedCountry: Either<DomainError, string> = right('US'); return pipe( TaskEither.right(validatedCountry), chain(fetchUsersByCountry) // 类型不兼容 ); };
修复方法1:在chain中处理Either的分支
const getUsers = (): TaskEither<Error, Option<User[]>> => { const validatedCountry: Either<DomainError, string> = right('US'); return pipe( TaskEither.right(validatedCountry), chain((eitherCountry) => eitherCountry.match( // 处理DomainError,转为Error类型的左值 (err) => TaskEither.left(new Error(`Invalid country: ${err.type}`)), // 成功时调用原函数 (country) => fetchUsersByCountry(country) ) ) ); };
修复方法2:先将Either转为TaskEither再链式调用
import { fromEither } from 'fp-ts/TaskEither'; import { chainW } from 'fp-ts/TaskEither'; const getUsers = (): TaskEither<Error, Option<User[]>> => { const validatedCountry: Either<DomainError, string> = right('US'); return pipe( // 将Either转为TaskEither<DomainError, string> fromEither(validatedCountry), // 用chainW兼容错误类型(DomainError → Error) chainW(fetchUsersByCountry) ); };
内容的提问来源于stack exchange,提问作者user1790300
相关产品推荐
相关产品推荐

