Johnson Lai avatar

Quick simple guide on making Redux-Observable works with TypeScript

superoo7

Published: 24 Jan 2019 › Updated: 24 Jan 2019Quick simple guide on making Redux-Observable works with TypeScript

Quick simple guide on making Redux-Observable works with TypeScript

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

1_fdzQpORTUt1yCFFOvD_whg.png

Image Credit

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);
  })

Leave Quick simple guide on making Redux-Observable works with TypeScript to:

Written by

Software Developer @ Coingecko

Read more #javascript posts


Best Posts From Johnson Lai

We have not curated any of superoo7's posts yet. But you can encourage our curation team to review posts by visiting them regularly and by referring other readers. Because we give priority to frequently read content.

More Posts From Johnson Lai