typescript - 如何创建使用 typesafe-actions AsyncCreator 的通用异步请求史诗来简化在 Redux 中处理 api 请求流
问题描述
我是一个新手,正在努力理解将史诗与 Typescript redux 环境中的异步操作相关联的最佳架构......
是否可以为给定的类型安全操作 AsyncCreator 实例创建通用异步请求史诗?
我已经尝试使用下面的代码,但丢失了关于操作有效负载的类型信息......只有类型属性在过滤的动作中被识别......我收到的转译错误是......
Property 'payload' does not exist on type 'ReturnType<[TRequestPayload] extends [undefined] ? unknown extends TRequestPayload ? PayloadAC<TRequestType, TRequestPayload> : EmptyAC<TRequestType> : PayloadAC<TRequestType, TRequestPayload>>'.
const createAsyncEpic = <
TModel, // generic type for data payload
TRequestType extends string,
TRequestPayload extends ApiRequest<TModel>,
TSuccessType extends string,
TSuccessPayload extends ApiSuccess<TModel>,
TFailureType extends string,
TFailurePayload extends ApiFailure<TModel>
>(
asyncAction: AsyncActionCreator<
[TRequestType, TRequestPayload],
[TSuccessType, TSuccessPayload],
[TFailureType, TFailurePayload]
>,
) => {
const epic: Epic<RootAction, RootAction, RootState, Services> = (
action$,
state$,
{ apiService },
) =>
action$.pipe(
filter(isActionOf(asyncAction.request)),
switchMap(action =>
apiService
.api()
.all<TModel>(action.payload.url) // property payload unrecognised, only type property recognised here
.pipe(
map(response => asyncAction.success(response.data)),
catchError(error =>
of(
asyncAction.failure(error),
),
),
),
),
);
return epic;
};
有没有人实现了这一点,而不是为每个资源的每个单独的 api 操作类型创建史诗?例如,为每个流程显式创建史诗:
- [FETCH_TODO_REQUEST,FETCH_TODO_SUCCESS,FETCH_TODO_FAILURE],
- [POST_TODO_REQUEST, POST_TODO_SUCCESS, POST_TODO_FAILURE].......,
- [FETCH_POST_REQUEST,FETCH_POST_SUCCESS,FETCH_POST_FAILURE],
- [PUT_POST_REQUEST、PUT_POST_SUCCESS、PUT_POST_FAILURE]........等等。
更新信息
稍微接近.... 修改方法函数签名以接受数据模型类型。
const createAsyncEpic = <
TModel // generic type for data payload model
>(
asyncAction: AsyncActionCreator<
[string, ApiRequest<TModel>],
[string, ApiSuccess<TModel | TModel[]>],
[string, ApiFailure<TModel>]
>,
) => {
const epic: Epic<RootAction, RootAction, RootState, Services> = (
action$,
state$,
{ courseServices, apiService },
) =>
action$.pipe(
filter(isActionOf(asyncAction.request)),
switchMap(action =>
apiService
.api()
.all<TModel>(action.payload.url)
.pipe(
map(resp =>
asyncAction.success({
request: action.payload, // Api request struct
response: resp, // Axios Response
}),
),
catchError(error =>
of(asyncAction.failure(action.payload.fail(error))),
),
),
),
);
return epic;
};
现在得到一个不同的错误:
ERROR in <path>/epics.ts
[tsl] ERROR in <path>/epics.ts(42,5)
TS2322: Type 'Observable<PayloadAction<TSuccessType, ApiSuccess<TModel | TModel[]>>>' is not assignable to type 'Observable<PayloadAction<actions.FETCH_COURSES_REQUEST, RequestingComponent> | PayloadAction<actions.FETCH_COURSES_SUCCESS, Course[]> | PayloadAction<constants.NOTIFY_ERROR, ErrorReport> | PayloadAction<string, ApiSuccess<Course>> | { ...; } | { ...; } | PayloadAction<...> | PayloadAction<...>>'.
Type 'PayloadAction<TSuccessType, ApiSuccess<TModel | TModel[]>>' is not assignable to type 'PayloadAction<actions.FETCH_COURSES_REQUEST, RequestingComponent> | PayloadAction<actions.FETCH_COURSES_SUCCESS, Course[]> | PayloadAction<constants.NOTIFY_ERROR, ErrorReport> | PayloadAction<string, ApiSuccess<Course>> | { ...; } | { ...; } | PayloadAction<...> | PayloadAction<...>'.
Type 'PayloadAction<TSuccessType, ApiSuccess<TModel | TModel[]>>' is not assignable to type 'PayloadAction<actions.FETCH_COURSES_REQUEST, RequestingComponent>'.
Type 'TSuccessType' is not assignable to type 'actions.FETCH_COURSES_REQUEST'.
Type 'string' is not assignable to type 'actions.FETCH_COURSES_REQUEST'.
是否与将史诗中使用的通用动作与史诗类型声明中的 RootAction 类型相匹配?
export declare interface Epic<Input extends Action = any, Output extends Input = Input, State = any, Dependencies = any> {
(action$: ActionsObservable<Input>, state$: StateObservable<State>, dependencies: Dependencies): Observable<Output>;
}
解决方案
解决了它并设法让它编译。这是一个类型声明问题。
使用 Typescript 时,史诗签名中声明的动作类型必须是设置中间件时声明的所有动作类型的子集。
我没有实例化新的通用动作的实例,也没有将它作为类型添加到 RootAction(所有动作类型的联合)。在重构之前,RootAction 还包含一些来自旧架构的旧动作类型。
执行此操作并将我的史诗签名重构为:
- 指定作为史诗输入接受的动作类型的子集
- 指定史诗输出的动作类型子集
我现在有一个史诗般的从 api 检索资源列表的史诗。其他史诗可以跟随补丁、发布、放置操作等。
推荐阅读
- python - 实现接收数组并将每个元素乘以给定 int 的函数
- python - 访问 argparse 的类属性文档字符串
- java - 如何设置意图以便我可以将数据发送到第二个活动并从那里发送到第三个活动?
- javascript - 尝试使用离子应用程序登录到 Azure AD 时出现 CORS 问题
- python - gUnicorn/gevent:请求库抛出 RecursionError:超出最大递归深度
- sql - 第二个“其他人失败时的例外”
- django - 具有静态相关模型集的用户模型
- javascript - 如何以反时钟方式循环二维数组?
- cookies - Auth0 - 注销时删除会话 cookie
- python - 多视图设置到路由器 Django 休息框架中