esamattis / redux-hooks

⚓ React Hooks implementation for Redux
http://npm.im/@epeli/redux-hooks
MIT License
96 stars 4 forks source link

TS2322 type error using HooksProvider together with immer-reducer #3

Closed sykesd closed 5 years ago

sykesd commented 5 years ago

@epeli Thanks for this an immer-reducer. The combination looks great and I hope for it to be able to reduce the boilerplate we have in a lot of our code.

I was trying this out today on a simple example, and I keep getting a TS2322 error on the line:

const store = createMyStore();   // Simple store with a single ImmerReducer-created render function

const renderApp = () => (
  <HookesProvider store={store}>    // <-- error here!!
    <MyStateUsingComponent />
  </HooksProvider>
);

The createMyStore function looks like this:

import {createUseMapState} from "@epeli/redux-hooks";
import { createStore } from "redux";
import { ProcedureSearchState, reducerFunction } from "./state";

export const useSearchState = createUseMapState<ProcedureSearchState>();

export const createSearchStore = () => createStore(reducerFunction);

The renderFunction and ProcedureSearchState look like this:

import { createActionCreators, createReducerFunction, ImmerReducer } from "immer-reducer";

export interface Procedure {
    readonly id: string;
    readonly name: string;
}

export interface ProcedureSearchState {
    readonly loading: boolean;
    readonly procedures: Procedure[];
    readonly query: string;
}

export const initialState: ProcedureSearchState = {
    loading: false,
    procedures: [],
    query: "",
};

export class ProcedureSearchReducer extends ImmerReducer<ProcedureSearchState> {
    public setQuery(query: string) {
        this.draftState.query = query;
    }

    public loadProcedures() {
        this.draftState.loading = true;
    }

    public receiveProcedures(procedures: Procedure[]) {
        this.draftState.procedures = procedures || [];
        this.draftState.loading = false;
    }
}

export const ActionCreators = createActionCreators(ProcedureSearchReducer);
export const reducerFunction = createReducerFunction(ProcedureSearchReducer, initialState);

The full error message is:

src/index.tsx:9:20 - error TS2322: Type 'Store<ProcedureSearchState, { type: "setQuery"; payload: string; } | { type: "loadProcedures"; payload: []; } | { type: "receiveProcedures"; payload: Procedure[]; }>' is not assignable to type 'Store<any, AnyAction>'.
  Types of property 'dispatch' are incompatible.
    Type 'Dispatch<{ type: "setQuery"; payload: string; } | { type: "loadProcedures"; payload: []; } | { type: "receiveProcedures"; payload: Procedure[]; }>' is not assignable to type 'Dispatch<AnyAction>'.
      Type 'AnyAction' is not assignable to type '{ type: "setQuery"; payload: string; } | { type: loadProcedures"; payload: []; } | { type: "receiveProcedures"; payload: Procedure[]; }'.
        Type 'AnyAction' is not assignable to type '{ type: "receiveProcedures"; payload: Procedure[]; }'.

9     <HooksProvider store={store}>
                     ~~~~~

  node_modules/immer-reducer/lib/immer-reducer.d.ts:50:9
    50         payload: FirstOrAll<Payload>;
               ~~~~~~~
    'payload' is declared here.
  node_modules/@epeli/redux-hooks/lib/redux-hooks.d.ts:18:5
    18     store: Store;
           ~~~~~
    The expected type comes from property 'store' which is declared here on type 'IntrinsicAttributes & { store: Store<any, AnyAction>; children: ReactNode; }'

I tried created a CodeSandox showing the error, but of course I don't get an error there.

I made sure I had the same tsconfig.json as your example here, but it made no difference. I still get the compiler error.

What am I doing wrong? What other information do you need to help me debug this?

The demos and the description of this look really great, and I would really like to try it out on a more substantial example once I get the very basics working.

sykesd commented 5 years ago

Just an update. I can remove the compiler error by changing my createSearchStore() function to be:

import { Store } from "redux";
...
export const createSearchStore = () => createStore(reducerFunction) as unknown as Store;

but you don't do this in your example, unless your composeReducers ends up having this effect?

esamattis commented 5 years ago

Interesting. The store prop is just the Store type from Redux:

https://github.com/epeli/redux-hooks/blob/8c76fa3b2c3ef442e0b87798436a57706cd7333a/src/redux-hooks.tsx#L96

But I guess we just loosen that type a bit since here's no need infer state or actions from it.

esamattis commented 5 years ago

Loosened the store requirements in 0.5.1. Does it fix it for you?

sykesd commented 5 years ago

Yes it does. Thank you. Upgraded to 0.5.2 and I was able to remove the 'as unknown as Store' type assertion.

Thanks.