Skip to content
Advertisement

Is is possible to use an typescript Union type for the state of a Redux Toolkit Slice?

I’d like to use an union type like this to represent my slice’s state when using Redux Toolkit:

type AppState = { loading: true } | { loading: false; data: number };

It seems like the usage of Immerjs in the reducer files prevents me from switching between the two Union options, e.g.:

import { createSlice, PayloadAction } from "@reduxjs/toolkit";

const initialState: AppState = { loading: true };

export const sampleSlice = createSlice({
  name: "sample",
  initialState,
  reducers: {
    setup: (state) => {
      return { loading: false, data: 5 };
    },
  },
});

Which gives me the following Typescript error:

Type '(state: WritableDraft<{ loading: true; }>) => { loading: false; data: number; }' is not assignable to type 'CaseReducer<{ loading: true; }, { payload: any; type: string; }> | CaseReducerWithPrepare<{ loading: true; }, PayloadAction<any, string, any, any>>'.

Is there any way to make this work? My current workaround is not using an union type to represent the state but I’m wondering if there is a workaround. I have also tried not using booleans but string literals for the loading key but it produces the same error.

Advertisement

Answer

NOTE: Per the docs, Option 2 is the better approach.

Option 1. Provide the generic parameter types for createSlice.

import { createSlice, SliceCaseReducers } from '@reduxjs/toolkit';

type AppState = { loading: true } | { loading: false; data: number };

const initialState: AppState = { loading: true };

type CaseReducers = SliceCaseReducers<AppState>;

export const sampleSlice = createSlice<AppState, CaseReducers>({
  name: 'sample',
  initialState,
  reducers: {
    setup: (state) => {
      return { loading: false, data: 5 };
    },
  },
});

The state type in case reducer:

enter image description here

Option 2. Cast the initial state. See Defining the Initial State Type

import { createSlice, SliceCaseReducers } from '@reduxjs/toolkit';

type AppState = { loading: true } | { loading: false; data: number };

const initialState: AppState = { loading: true };

// type CaseReducers = SliceCaseReducers<AppState>;

export const sampleSlice = createSlice({
  name: 'sample',
  initialState: initialState as AppState,
  reducers: {
    setup: (state) => {
      return { loading: false, data: 5 };
    },
  },
});

package versions:

"@reduxjs/toolkit": "^1.6.1",
"typescript": "^4.3.5",
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement