Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

typings issue between createSlice and configureStore's reducer prop ? #102

Closed
Sharlaan opened this issue Jan 26, 2019 · 9 comments
Closed

Comments

@Sharlaan
Copy link

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
@markerikson
Copy link
Collaborator

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.)

@denisw
Copy link
Contributor

denisw commented Jan 27, 2019

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.

@denisw
Copy link
Contributor

denisw commented Jan 27, 2019

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.

@Sharlaan
Copy link
Author

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.

markerikson pushed a commit that referenced this issue Jan 27, 2019
This is more correct as the generated reducer does, in fact,
support passing actions other than the ones explicitly handled.
Also, this fixes an incompatibility with `configureStore` (#102).
@markerikson
Copy link
Collaborator

Just published this as 0.4.3. Thanks!

@TidyIQ
Copy link

TidyIQ commented Jul 12, 2019

I'm getting the same error in v0.5.1

@TidyIQ
Copy link

TidyIQ commented Jul 12, 2019

// 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>'

@TidyIQ
Copy link

TidyIQ commented Jul 12, 2019

Oh wait, nevermind. I needed to change

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

to

const reducer = {
  snackbar: snackbarReducer.reducer
};

markerikson pushed a commit that referenced this issue Apr 20, 2021
* enhanceEndpoints RFC

* add entityTypes to enhanceEndpoints

* refactor tests

* only allow to add new entityTypes, don't allow to remove any

* keep console clean

* add documentation for code generation

* Add code gen to sidebar and link to createApi

Co-authored-by: Matt Sutkowski <msutkowski@gmail.com>
@wmcooper2
Copy link

I had a similar problem. My solution was stupidly simple even though it caused me a headache for a couple hours.
I was importing a default export incorrectly. I assumed it was a problem with my TypeScript types, but it ended up being a problem with my brain.

My mistake: importing using braces on a default export

// where I was importing it
import { alertSlice } from './alert/slice';

export const store = configureStore({
    reducer: {
        //...
        alerts: alertSlice
    },
});
// where it was being exported
//...
export default alertSlice.reducer;

Solution: just remove the braces

import alertSlice from './alert/slice';

export const store = configureStore({
    reducer: {
        //...
        alerts: alertSlice
    },
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants