Redux-toolkit: How to integrate redux-observable with typescript?

Created on 24 Oct 2019  路  13Comments  路  Source: reduxjs/redux-toolkit

I am currently trying to find a way to integrate redux-observable with typescript.
It looks like I need to specify a root epic type for the observable-middleware like this epicMiddleWare<RootAction, RootAction, RootState>.

Unfortunately I am not quite sure how I can build a union type of all my actions created with createSlice so that it is usable by the observable-middleware. Can you point me into any direction of how to integrate redux-observable?

Most helpful comment

Seems reasonable to me. Will try to look at the couple open PRs this evening.

All 13 comments

Hmm. I haven't worked with redux-observable myself. You might get a better answer asking over on that repo.

The generated action types are available as someSlice.actions.someActionCreator.type. You should be able to somehow define a union of all of those.

Alright - thanks for the quick response :)

I'll head over to the observable repo and ask my question there. If I find a good way to solve this I'll leave another comment here :+1:

@markerikson am I correct in assuming, that the action types produced by createSlice are just string and no type specific constants? That would mean that it is impossible to narrow down action types inside other functions if I am not mistaken? (I am by no means a typescript expert)

As far as I know, yes. That's because we're concatenating together two strings to generate the type, not defining a specific literal up front.

@phryneas could confirm.

As typescript can not concatenate literal string types, yes, we cannot generate those. There are multiple issues over in the TS repo on that.

@phryneas that looks like it might work :)

Then let's see what @markerikson thinks about it :)

Seems reasonable to me. Will try to look at the couple open PRs this evening.

I found a neat solution for getting the RootAction type from actions - you can take the union type of all your action in the form ReturnType

@erodactyl Code or it did not _happen_. :D

Well, here you go :D

````
export const addMessageAction = createAction(
"AddMessage",
(body: string, conversationId: string) => ({
payload: { body, conversationId },
})
);

export type Action =
| ReturnType
| ReturnType
| ReturnType;
````

and then

const epic: Epic<Action, Action, void, Dependencies> = ....

You can create the RootAction using 'ValuesType' from utility-types on the actions object from each slice.

import { ValuesType } from 'utility-types'
import { createSlice, PayloadAction } from '@reduxjs/toolkit'

const sliceA = createSlice({
  name: 'SliceA',
  initialState: { result: 0 },
  reducers: {
    add: (state, action: PayloadAction<number>) => {
      state.result += action.payload
    },
    subtract: (state, action: PayloadAction<number>) => {
      state.result -= action.payload
    },
  },
})

const sliceB = createSlice({
  name: 'SliceB',
  initialState: { count: 0 },
  reducers: {
    increment: state => {
      state.count += 1
    },
    decrement: state => {
      state.count -= 1
    },
  },
})

export type RootAction =
  | ValuesType<typeof sliceA['actions']>
  | ValuesType<typeof sliceB['actions']>
Was this page helpful?
0 / 5 - 0 ratings