如何正确为fp-ts ObservableEither#fold添加类型,避免转AnyAction?
解决思路
你遇到的类型报错本质是fold操作符默认要求错误分支和成功分支的返回值类型完全一致,而loginFail和loginSuccess是两种不同结构的Action,没有显式声明联合类型的情况下TS会强制要求类型对齐,因此触发报错。不需要强制转AnyAction,可以通过以下方案解决:
方案1:显式声明Action联合类型 + 指定Epic泛型
这是最通用的解决方案,首先将你所有可能返回的登录相关Action组合成联合类型,再给Redux Observable的Epic指定输出Action的泛型参数,TS会自动识别兼容两种返回类型:
// LoginSlice.ts 导出所有action后,在LoginEpics.ts中定义联合类型 type LoginAction = | ReturnType<typeof loginSuccess> | ReturnType<typeof loginFail> // 给Epic指定泛型:<输入Action类型, 输出Action类型, RootState类型> export const loginEpic: Epic<AnyAction, LoginAction> = (action$) => action$.pipe( filter(login.match), mergeMap((action) => loginService(action.payload.credentials).pipe( fold( (error) => of(loginFail({ error })), (user) => of(loginSuccess({ user })) ) ) ) );
方案2:修复bimap的运行时错误
你之前用bimap报type为undefined的问题,是因为bimap返回的是ObservableEither<LoginFailAction, LoginSuccessAction>类型,没有解包为普通的Action Observable,Redux Observable无法识别内部的Action结构,只需要在bimap后追加fold解包即可:
export const loginEpic: Epic<AnyAction, LoginAction> = (action$) => action$.pipe( filter(login.match), mergeMap((action) => loginService(action.payload.credentials).pipe( bimap( (error) => loginFail({ error }), (user) => loginSuccess({ user }) ), // 解包ObservableEither,将两个分支的Action都转为普通Observable发射 fold((failAction) => of(failAction), (successAction) => of(successAction)) ) ) );
方案3:显式指定fold的泛型参数
如果你不想额外定义联合类型,也可以在调用fold时直接指定返回值的泛型,强制让TS识别两个分支的返回值为兼容的Action联合:
export const loginEpic: Epic = (action$) => action$.pipe( filter(login.match), mergeMap((action) => loginService(action.payload.credentials).pipe( // 直接指定fold的第三个泛型为返回的Observable类型 fold<Error, User, Observable<ReturnType<typeof loginSuccess> | ReturnType<typeof loginFail>>>( (error) => of(loginFail({ error })), (user) => of(loginSuccess({ user })) ) ) ) );
内容的提问来源于stack exchange,提问作者George S
相关产品推荐
相关产品推荐

