如何正确输入 fp-ts Observable Either#fold?
How to properly type fp-ts ObservableEither#fold?
我正在尝试使用 fp-ts 和 redux-observable 构建一些 epics 来处理一些 api 请求。我在使用 fp-ts-rxjs/ObservableEither#fold 时遇到问题,如果我不将我的操作转换为 AnyAction
类型,我会收到一个类型错误,指出这两种类型应该是相同的。
Type 'Observable<{ payload: { user: User<Attributes>; }; type: string; }>' is not assignable to type 'Observable<{ payload: { error: Error | null; }; type: string; }>'.
Type '{ payload: { user: User<Attributes>; }; type: string; }' is not assignable to type '{ payload: { error: Error | null; }; type: string; }'.
Types of property 'payload' are incompatible.
Property 'error' is missing in type '{ user: User<Attributes>; }' but required in type '{ error: Error | null; }'
我也尝试过使用 fp-ts-rxjs/ObservableEither#bimap,因为它期望返回两种不同的类型。但是,这会导致运行时错误,指出操作不能具有未定义的类型。我也不确定那里到底发生了什么。
LoginSlice.ts
const loginSlice = createSlice({
name: 'login',
initialState,
reducers: {
loginSuccess (state, action: PayloadAction<{ user: User }>) {
state.loggedIn = true;
},
loginReset (state) {
state.error = null;
},
loginFail (state, action: PayloadAction<{ error: Error | null } >) {
state.error = action.payload.error;
}
}
});
LoginService.ts
const loginService = (credentials: LoginInfo): OE.ObservableEither<Error, User> => {
const { username, password } = credentials;
return OE.fromTaskEither(
TE.tryCatch(
async () => await User.logIn(username, password),
error => error as Error
)
);
};
LoginEpics.ts
export const loginEpic: Epic = (action$: ActionsObservable<AnyAction>) => action$.pipe(
filter(login.match),
mergeMap((action) =>
loginService(action.payload.credentials).pipe(
fold(
(error) => of(loginFail({ error }) as AnyAction),
(user) => of(loginSuccess({ user }) as AnyAction)
)
)
)
);
有没有办法避免将动作转换为 AnyAction
?任何见解将不胜感激。
我不熟悉 fp-ts-rxjs/ObservableEither
,但是如果它们的 fold
函数的定义与常规 fp-ts
折叠函数的定义方式类似,我认为您的问题可以通过指定来解决来自您传递给 fold
.
的一个或两个匿名函数的确切 return 类型
当没有指定 return 类型时,TypeScript 会尝试从第一个函数推断出 return 类型,但不够聪明,无法意识到这一点,因为两个匿名函数 return 不同类型,折叠结果应该是两个 return 类型的并集。
假设您有 LoginFailure
和 LoginSuccess
动作类型,没有 AnyAction
的折叠看起来像:
fold(
(error): LoginFailure | LoginSuccess => of(loginFail({ error })),
(user): LoginFailure | LoginSuccess => of(loginSuccess({ user }))
)
这里我们指定 return 类型应该是可能的 returned 操作的联合。
我正在尝试使用 fp-ts 和 redux-observable 构建一些 epics 来处理一些 api 请求。我在使用 fp-ts-rxjs/ObservableEither#fold 时遇到问题,如果我不将我的操作转换为 AnyAction
类型,我会收到一个类型错误,指出这两种类型应该是相同的。
Type 'Observable<{ payload: { user: User<Attributes>; }; type: string; }>' is not assignable to type 'Observable<{ payload: { error: Error | null; }; type: string; }>'.
Type '{ payload: { user: User<Attributes>; }; type: string; }' is not assignable to type '{ payload: { error: Error | null; }; type: string; }'.
Types of property 'payload' are incompatible.
Property 'error' is missing in type '{ user: User<Attributes>; }' but required in type '{ error: Error | null; }'
我也尝试过使用 fp-ts-rxjs/ObservableEither#bimap,因为它期望返回两种不同的类型。但是,这会导致运行时错误,指出操作不能具有未定义的类型。我也不确定那里到底发生了什么。
LoginSlice.ts
const loginSlice = createSlice({
name: 'login',
initialState,
reducers: {
loginSuccess (state, action: PayloadAction<{ user: User }>) {
state.loggedIn = true;
},
loginReset (state) {
state.error = null;
},
loginFail (state, action: PayloadAction<{ error: Error | null } >) {
state.error = action.payload.error;
}
}
});
LoginService.ts
const loginService = (credentials: LoginInfo): OE.ObservableEither<Error, User> => {
const { username, password } = credentials;
return OE.fromTaskEither(
TE.tryCatch(
async () => await User.logIn(username, password),
error => error as Error
)
);
};
LoginEpics.ts
export const loginEpic: Epic = (action$: ActionsObservable<AnyAction>) => action$.pipe(
filter(login.match),
mergeMap((action) =>
loginService(action.payload.credentials).pipe(
fold(
(error) => of(loginFail({ error }) as AnyAction),
(user) => of(loginSuccess({ user }) as AnyAction)
)
)
)
);
有没有办法避免将动作转换为 AnyAction
?任何见解将不胜感激。
我不熟悉 fp-ts-rxjs/ObservableEither
,但是如果它们的 fold
函数的定义与常规 fp-ts
折叠函数的定义方式类似,我认为您的问题可以通过指定来解决来自您传递给 fold
.
当没有指定 return 类型时,TypeScript 会尝试从第一个函数推断出 return 类型,但不够聪明,无法意识到这一点,因为两个匿名函数 return 不同类型,折叠结果应该是两个 return 类型的并集。
假设您有 LoginFailure
和 LoginSuccess
动作类型,没有 AnyAction
的折叠看起来像:
fold(
(error): LoginFailure | LoginSuccess => of(loginFail({ error })),
(user): LoginFailure | LoginSuccess => of(loginSuccess({ user }))
)
这里我们指定 return 类型应该是可能的 returned 操作的联合。