如何创建使用类型安全动作AsyncCreator简化Redux中api请求流的处理的通用异步请求史诗

问题描述 投票:1回答:1

我是一个新手,正在努力了解将史诗与Typescript redux环境中的异步操作相关联的最佳体系结构。...

是否可以为给定的typesafe-actions AsyncCreator实例创建通用的异步请求史诗?

我尝试了下面的代码,但是丢失了操作有效载荷上的类型信息。...在过滤后的操作上只能识别type属性。...我收到的翻译错误是...

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操作类型创建史诗的替代方法吗?例如,为每个流显式创建一个史诗:

  1. [FETCH_TODO_REQUEST,FETCH_TODO_SUCCESS,FETCH_TODO_FAILURE],
  2. [[POST_TODO_REQUEST,POST_TODO_SUCCESS,POST_TODO_FAILURE] .......,
  3. [[FETCH_POST_REQUEST,FETCH_POST_SUCCESS,FETCH_POST_FAILURE],
  4. [[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'.

与将史诗中使用的通用动作与Epic类型声明中的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 redux redux-observable typesafe-actions
1个回答
0
投票

已解决,并设法将其编译。这是一个类型声明问题。

[使用Typescript时,史诗签名中声明的动作类型必须是在设置中间件时声明的所有动作类型的子集。

我没有实例化新通用操作的实例,也没有将它作为类型添加到RootAction(所有操作类型的联合)中。在重构之前,RootAction还仍然包含一些来自旧体系结构的旧操作类型。

执行此操作并将我的史诗签名重构为以下代码后进行编译:-指定接受作为史诗输入的动作类型的子集-指定史诗输出的动作类型的子集

© www.soinside.com 2019 - 2024. All rights reserved.