Redux-toolkit: typings issue between createSlice and configureStore's reducer prop ?

Created on 26 Jan 2019  路  8Comments  路  Source: reduxjs/redux-toolkit

I'm trying to integrate RSK in a minimal Typescript project, but i stumbled upon what looks like a typing conflict :

Apparently configureStore.reducer expects to use AnyAction interface while createSlice reducer uses PayloadAction.
I'm a bit new in TS i don't see how to solve this conflict.

deps :

  • redux-starter-kit 0.4.2
  • typescript 3.2.4

Most helpful comment

Oh wait, nevermind. I needed to change

// reducer.ts
const reducer = {
  snackbar: snackbarReducer
};

to

const reducer = {
  snackbar: snackbarReducer.reducer
};

All 8 comments

Paging the TS crew: @denisw @Dudeonyx @jessidhia .

(I will say this is the kind of thing I was kinda concerned about with switching the code to TS: questions I have no way to help answer myself.)

The type error here isn't about PayloadAction vs. AnyAction; the former is a subtype of the latter, so the types are compatible in this respect. But looking at the error message, the problem seems to be that we are not handling the "pass an object instead of a reducer function" correctly, as it says:

{ counter: Reducer<number, ...> } not assignable to Reducer<{ counter: number }, ...>

We should be accepting the object and inferring from the object shape what the store's state type is, but that doesn't seem to be quite working. I'll investigate.

Sorry, you were right @Sharlaan - it's really the action type that was the issue. I failed to realise that the reducer's action type parameter must be a _supertype_ of the store action type (it has to be able to accept every store action), which is not the case if the reducer takes only PayloadAction.

I created #104 to fix this.

Ok nice ! Glad it helped.

At the moment i'm trying to find an elegant way to type State.

Would definitely need an example of typing integration along react-redux.

Just published this as 0.4.3. Thanks!

I'm getting the same error in v0.5.1

// slices/snackbar.ts

import { createSlice, PayloadAction } from "redux-starter-kit";

export interface SnackbarState {
  message: string;
  open: boolean;
  undo: null | (() => void);
  variant: "success" | "warning" | "error" | "info";
}

const initialSnackbarState: SnackbarState = {
  message: "",
  open: false,
  undo: null,
  variant: "info"
};

type OpenSnackbarAction = PayloadAction<SnackbarState>;
type CloseSnackbarAction = PayloadAction<Pick<SnackbarState, "open">>;

const snackbarReducer = createSlice({
  slice: "snackbar",
  reducers: {
    openSnackbar: (_state, action: OpenSnackbarAction) => {
      _state = action.payload;
    },
    closeSnackbar: (state, action: CloseSnackbarAction) => {
      state.open = action.payload.open;
    }
  },
  initialState: initialSnackbarState
});

export default snackbarReducer;
// reducer.ts

import snackbarReducer from "./slices/snackbar";

const reducer = {
  snackbar: snackbarReducer
};

export default reducer;
// store.ts

import { configureStore } from "redux-starter-kit";
import reducer from "./reducer";

const store = configureStore({
  reducer
});

export default store;
// Error for store.ts

Type '{ snackbar: Slice<SnackbarState, CaseReducerActionPayloads<{ openSnackbar: (_state: { message: string; open: boolean; undo: (() => void) | null; variant: "success" | "warning" | "error" | "info"; }, action: PayloadAction<SnackbarState, string>) => void; closeSnackbar: (state: { ...; }, action: PayloadAction<...>) =>...' is not assignable to type 'Reducer<{ snackbar: unknown; }, AnyAction> | ReducersMapObject<{ snackbar: unknown; }, AnyAction>'.
  Type '{ snackbar: Slice<SnackbarState, CaseReducerActionPayloads<{ openSnackbar: (_state: { message: string; open: boolean; undo: (() => void) | null; variant: "success" | "warning" | "error" | "info"; }, action: PayloadAction<SnackbarState, string>) => void; closeSnackbar: (state: { ...; }, action: PayloadAction<...>) =>...' is not assignable to type 'ReducersMapObject<{ snackbar: unknown; }, AnyAction>'.
    Types of property 'snackbar' are incompatible.
      Type 'Slice<SnackbarState, CaseReducerActionPayloads<{ openSnackbar: (_state: { message: string; open: boolean; undo: (() => void) | null; variant: "success" | "warning" | "error" | "info"; }, action: PayloadAction<SnackbarState, string>) => void; closeSnackbar: (state: { ...; }, action: PayloadAction<...>) => void; }>>' is not assignable to type 'Reducer<unknown, AnyAction>'.
        Type 'Slice<SnackbarState, CaseReducerActionPayloads<{ openSnackbar: (_state: { message: string; open: boolean; undo: (() => void) | null; variant: "success" | "warning" | "error" | "info"; }, action: PayloadAction<SnackbarState, string>) => void; closeSnackbar: (state: { ...; }, action: PayloadAction<...>) => void; }>>' provides no match for the signature '(state: unknown, action: AnyAction): unknown'.

The expected type comes from property 'reducer' which is declared here on type 'ConfigureStoreOptions<{ snackbar: unknown; }, AnyAction>'

Oh wait, nevermind. I needed to change

// reducer.ts
const reducer = {
  snackbar: snackbarReducer
};

to

const reducer = {
  snackbar: snackbarReducer.reducer
};
Was this page helpful?
0 / 5 - 0 ratings