I'm setting TypeScript and Redux-Observable in my app and have this simple flow I'd like to apply here with an Epic:
dispatch('someAction')
fetch('relevant-endpoint-from-api')
getResponse(dispatch('someActionSuccess'))
failed(dispatch('someActionFailed'))
So following this article that is just doing that, I gave it a try.
Here's my actions.ts file:
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
And then my epic.ts file:
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)
I'm new to TypeScript so maybe the error seems obvious to aficionados, but I don't get what I've done wrong based on TypeScript's message.
(no longer relevant) The message points at the action$
returned in the epic:
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
I don't get what I could do to fix this, from the message it seems that all I've done is wrong and that medias is unknown although it's specified as being an array of MediasOrigin
in the interface. Am I missing something here?
For information, here are the packages versions:
- typescript: 4.0.2
- redux-observable: 1.2.0
- rxjs: 6.6.3
// Edit: 09/24/2020
I made a couple changes in order to make it simpler and got why the error message was talking about a mediasUnknown: I wasn't telling in the epic that response mapped from the api call was of MediasOrigin[]
(renamed IMediasOrigin[] now). Also I removed the api
method that was a custom operator of my own. Changes have been brought to the scripts above and signaled with a // change
comment.
Here's now the error message:
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
From what I get, it seems like there is a conflict between my IMediasOriginsFetchAllSuccessAction and IMediasOriginsFetchAllFailedAction at the payload level which makes one of them not assignable to type MediasAction. But isn't that the whole purpose of the | operator when creating types?