This is a guide I written on stack overflow, which I plan to rewrite it into a simple post.
You can checkout React Redux Typescript Guide for the details in here for all the standard way of doing when using React, Redux and Redux-Observable.
Introduction
This guide I would like to talk a bit about using Redux-Observable alongside with TypeScript and make the types work out of the box.
I will be using typesafe-actions
library to achieve the types. (GitHub for typesafe-actions)
Actions
Instead of declaring interface (types) expressively, (something like below)
export interface LoginSuccessAction extends Action { type: LoginActionTypes.LOGIN_SUCCESS_ACTION; payload: { loginToken: string; };}export function loginSuccess(loginToken: string): LoginSuccessAction { return { type: LoginActionTypes.LOGIN_SUCCESS_ACTION, payload: { loginToken }, };}
use typesafe-actions
library without declaring any interface.
actions/login/LoginActions.ts
import {action} from "typesafe-actions"export function loginSuccess(loginToken: string) { return action(LoginActionTypes.LOGIN_SUCCESS_ACTION, { loginToken });}
Then, all the login actions are being exported out in the model file.
actions/login/LoginActionsModel.ts
import * LoginActions from "./LoginActions";import { ActionCreator } from "typesafe-actions";export type LoginActionCreator = ActionCreator<typeof LoginActions>
Then export out all the actions as AllActions.
actions/index.ts
import { LoginActionCreator } from "./login/LoginActionModel";export default type AllActions = LoginActionCreator
Epics
In the epics, import following library.
import { Epic } from "redux-observable";import { isOfType } from "typesafe-actions";import { filter } from "rxjs/operators";
Then simply use Epic to declare your types.
export const loginUserEpic: Epic<AllActions> = (action$) => action$.pipe( filter(isOfType((LoginActionTypes.LOGIN_ACTION))), switchMap((action: LoginAction) => ajax({ url, method: 'POST', headers: { 'Content-Type': 'application/json' }, body: { email: action.payload.username, password: action.payload.password }, }).pipe( map((response: AjaxResponse) => loginSuccess(response.response.token)), catchError((error: Error) => of(loginFailed(error))), ), ), );
Where the Epics is from redux-observable
library, AllActions are the actions that is input and output of the epics.
The types is as follows:
Epic<InputActions, OutputActions, Store>Epic<Actions(Input&Output)>
In case you want to use store from redux, you need a RootState (from root reducer)
export const someEpic: Epic<AllActions, AllActions, RootState> = (action$, store$) => action$.pipe( filter(isOfType(SOMETYPE)), mergeMap(action => { const a = store$.value.a; return someActions(a, action.payload.b); })