如何使用TypeScript键入Redux-Observable的史诗动作

乌托邦

我在应用程序中设置TypeScript和Redux-Observable,并具有以下简单流程,我想在此处使用Epic进行应用:

dispatch('someAction')
fetch('relevant-endpoint-from-api')
getResponse(dispatch('someActionSuccess'))
failed(dispatch('someActionFailed'))

因此,按照本文的相关内容,我尝试了一下。

这是我的actions.ts文件:

export interface MediasOrigin {
  id: number;
  label: string;
  url: string;
  zonesId: number[];
  scenariosRef: number[];
  stepsRef: number[];
  gearsId: number[];
  texturesId: number[];
}

export enum MediasActionTypes {
  MEDIAS_ORIGINS_FETCH_ALL = "MEDIAS_ORIGINS_FETCH_ALL",
  MEDIAS_ORIGINS_FETCH_ALL_SUCCESS = "MEDIAS_ORIGINS_FETCH_ALL_SUCCESS",
  MEDIAS_ORIGINS_FETCH_ALL_FAILED = "MEDIAS_ORIGINS_FETCH_ALL_FAILED"
}

export interface IMediasOriginsFetchAllAction {
  type: MediasActionTypes.MEDIAS_ORIGINS_FETCH_ALL;
}

export interface IMediasOriginsFetchAllSuccessAction {
  type: MediasActionTypes.MEDIAS_ORIGINS_FETCH_ALL;
  payload: {
    medias: MediasOrigin[]
  }
}

export interface IMediasOriginsFetchAllFailedAction {
  type: MediasActionTypes.MEDIAS_ORIGINS_FETCH_ALL;
  payload: {
    error: string
  }
}

/* ACTION CREATOR */
export function fetchAllMediaOrigins(): IMediasOriginsFetchAllAction {
  return {
    type: MediasActionTypes.MEDIAS_ORIGINS_FETCH_ALL
  }
}

export type MediasAction = IMediasOriginsFetchAllAction | IMediasOriginsFetchAllSuccessAction | IMediasOriginsFetchAllFailedAction

然后我的epic.ts文件:

import { from, Observable, of } from "rxjs"
import { map, catchError, switchMap, filter } from "rxjs/operators"
import { isOfType } from "typesafe-actions"
import { Epic } from "redux-observable"

import ApiClient from "agent" // change, wrapper around superagent (http client)
import {IStore} from "reducers"
import {
  MediasAction,
  MediasActionTypes,
  IMediasOrigin
} from "./actions"

const getAllMediasOriginEpic: Epic<MediasAction, MediasAction, IStore> = action$ => {
  const request = new ApiClient();

  return action$.pipe(
    filter(isOfType(MediasActionTypes.MEDIAS_ORIGINS_FETCH_ALL)),
    switchMap(action => // change
      from(request.getAllOriginMedias()).pipe( // change
        map((response: IMediasOrigin[]) // change =>
          of({
            type: MediasActionTypes.MEDIAS_ORIGINS_FETCH_ALL_SUCCESS,
            payload: { medias: response },
          })
        ),
        catchError((error: Error) // change =>
          of({
            type: MediasActionTypes.MEDIAS_ORIGINS_FETCH_ALL_FAILED,
            payload: {error: Error.message}, // change
          })
        )
      )
    )
  )
}

export default combineEpics(getAllMediasOriginEpic)

我是TypeScript的新手,所以对于狂热者来说,错误似乎很明显,但是基于TypeScript的消息,我没有做错什么。

(不再相关)消息指向action$史诗中返回的内容:

Type 'Observable<IMediasOriginsFetchAllAction | Observable<{ type: MediasActionTypes; payload: { medias: unknown; }; }>>' is not assignable to type 'Observable<MediasAction>'.
  Type 'IMediasOriginsFetchAllAction | Observable<{ type: MediasActionTypes; payload: { medias: unknown; }; }>' is not assignable to type 'MediasAction'.
    Type 'Observable<{ type: MediasActionTypes; payload: { medias: unknown; }; }>' is not assignable to type 'MediasAction'.
      Type 'Observable<{ type: MediasActionTypes; payload: { medias: unknown; }; }>' is missing the following properties from type 'IMediasOriginsFetchAllSuccessAction': type, payload  TS2322

我没有办法解决这个问题,从消息看来,我所做的一切都是错误的,尽管MediasOrigin在接口中将其指定为数组,但媒体是未知的我在这里想念什么吗?

有关信息,请参见以下软件包版本:

  • 打字稿:4.0.2
  • 可观察到的redux:1.2.0
  • rxjs:6.6.3

//编辑:09/24/2020

为了简化起见,我进行了一些更改,并弄清了为什么错误消息谈论的是mediasUnknown:我没有在史诗中告诉从api调用映射的响应是MediasOrigin[](现在重命名为IMediasOrigin [])。我也删除了api自己的自定义运算符方法。上面的脚本中进行了更改,并带有// change注释。

现在是错误消息:

TypeScript error in /Users/utopiad/Dev/spectral-core/platform/src/components/Medias/epics.ts(11,7):
Type '(action$: ActionsObservable<MediasAction>) => Observable<Observable<{ type: MediasActionTypes; payload: { medias: IMediasOrigin[]; }; }> | { ...; }>' is not assignable to type 'Epic<MediasAction, MediasAction, IStore, any>'.
  Type 'Observable<Observable<{ type: MediasActionTypes; payload: { medias: IMediasOrigin[]; }; }> | { type: MediasActionTypes; payload: { ...; }; }>' is not assignable to type 'Observable<MediasAction>'.
    Type 'Observable<{ type: MediasActionTypes; payload: { medias: IMediasOrigin[]; }; }> | { type: MediasActionTypes; payload: { ...; }; }' is not assignable to type 'MediasAction'.
      Type 'Observable<{ type: MediasActionTypes; payload: { medias: IMediasOrigin[]; }; }>' is not assignable to type 'MediasAction'.
        Type 'Observable<{ type: MediasActionTypes; payload: { medias: IMediasOrigin[]; }; }>' is missing the following properties from type 'IMediasOriginsFetchAllFailedAction': type, payload

从我得到的结果来看,我的IMediasOriginsFetchAllSuccessAction和IMediasOriginsFetchAllFailedAction在有效负载级别之间似乎存在冲突,这使得其中之一无法分配为MediasAction类型。但这不是| |的全部目的。类型时使用运算符?

安德烈·盖特伊(AndreiGătej)

您可以通过在返回操作时添加以下内容as const解决此问题MediasActionTypes.*

const getAllMediasOriginEpic: Epic<MediasAction, MediasAction> = (action$) => {
  const request = new ApiClient();
  return action$.pipe(
    filter(isOfType(MediasActionTypes.MEDIAS_ORIGINS_FETCH_ALL)),
    switchMap((action) =>
      from(request.getAllOriginMedias()).pipe(
        map((response: IMediasOrigin[]) => ({
          type: MediasActionTypes.MEDIAS_ORIGINS_FETCH_ALL_SUCCESS as const,
          payload: { medias: response }
        })),
        catchError((error: Error) =>
          of({
            type: MediasActionTypes.MEDIAS_ORIGINS_FETCH_ALL_FAILED as const,
            payload: { error: error.message }
          })
        )
      )
    )
  );
};

这是因为当您使用以下内容时:

map((response: IMediasOrigin[]) => ({
    type: MediasActionTypes.MEDIAS_ORIGINS_FETCH_ALL_SUCCESS,
    payload: { medias: response }
  })),

Observable的类型为:{ type: MediasActionTypes }, ...如您所见,您的错误

Type 'MediasActionTypes' is not assignable to type 'MediasActionTypes.MEDIAS_ORIGINS_FETCH_ALL_FAILED'

'MediasActionTypes'是指工会,MediasActionTypes.MEDIAS_ORIGINS_FETCH_ALL_FAILED具体的类型。因此,通过使用type: MediasActionTypes.MEDIAS_ORIGINS_FETCH_ALL_SUCCESS as const您可以缩小类型。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

redux-observable-在单个史诗中调度多个redux动作

Redux-Observable 单个史诗中的多个动作

如何使用redux-observable在一部史诗中发出多个动作?

如何在 redux observable 史诗中为 ajax 响应发出两个动作

如何创建一个 redux-observable 史诗,在做任何事情之前等待 2 个动作

使用 redux-observable 和 rxjs 在史诗中出错

Redux可见的史诗,不会发送任何新动作

Redux可观察到的史诗链调度重复动作

如何使用Redux可观察的史诗来测量两次动作之间的持续时间?

可观察到的Redux-如何发送动作以启动单独的史诗,然后等待该史诗响应(或超时)

史诗未在Redux-Observable中返回流

为什么我的redux-observable史诗没有被触发?

可以确定史诗何时在 Redux Observable 中完成?

在Redux可观察到的史诗中的所有动作之后触发一个动作

如何在单个Redux可观察的史诗中等待/屈服于多个动作?

如何轻松测试5分钟后发出动作的redux可观察的史诗?

使用Redux可观察的史诗通过多个动作来装饰数据

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

redux-observable 调度动作

使用redux-observable调度多个动作

如何在史诗 redux-observable 的 componentDidMount 方法中设置状态数据

可观察到的Redux:为多个动作触发相同的史诗

Redux Observables:针对相同动作但不同过滤器的单独史诗?

在Redux可观察的史诗中发送请求之前触发动作

如何在同一个史诗中调度多个动作

使用带有类型安全动作和连接的 React 路由器的史诗

如何将使用typesafe-actions createAsyncAction创建的动作传递给生成具有正确类型的Redux可观察史诗的函数?

Redux-observable:在一些数据获取史诗完成后调用辅助函数

Redux Observable Fetching史诗中将超时运算符放在何处