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:
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",