#[Redux] ThunkDispatch is not liking my action call (code links inside)

4 messages · Page 1 of 1 (latest)

wispy cave
#

How should I be writing my AppDispatch type so that it accepts my presenter.loadPublicDecks() action call?

Directory and branch to review:
https://github.com/do-kevin/Zephyr-Node/tree/feature/mobx-to-redux/client2/src

store.ts

import { combineReducers } from "redux";
import { configureStore } from "@reduxjs/toolkit";
import decksReducer, { AppAction } from "../flashcard/DeckRepository";
import { HttpGateway } from "./http-gateway";
import { ThunkDispatch } from "redux-thunk";

const rootReducer = combineReducers({
  decksState: decksReducer,
});

export type RootState = ReturnType<typeof rootReducer>;

const store = (httpGateway: InstanceType<typeof HttpGateway>) => {
  return configureStore({
    reducer: rootReducer,
    middleware: (getDefaultMiddleware) =>
      getDefaultMiddleware({
        thunk: {
          extraArgument: {
            http: httpGateway,
          },
        },
      }),
  });
};

export type AppDispatch = ThunkDispatch<
  RootState,
  InstanceType<typeof HttpGateway>,
  AppAction
>;

export type AppGetState = () => RootState;

export default store;
#

DeckRepository.ts

import { HttpGateway } from "src/core/http-gateway";
import { AppDispatch, AppGetState, RootState } from "src/core/store";
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";

const DECKS_LOADED_PUBLIC = "DECKS_LOADED_PUBLIC";

export interface LoadPublicDeckAction {
  type: "DECKS_LOADED_PUBLIC";
  payload: {
    decksPM: Deck[];
  };
}

export type AppAction = LoadPublicDeckAction;

export const loadPublicDecks =
  () =>
  async (
    dispatch: AppDispatch,
    _getState: AppGetState,
    { http }: { http: HttpGateway }
  ) => {
    const url = `/decks/public`;

    const decksDTO = await http.get(url);
    const decksProgrammersModel = await decksDTO.json();

    console.log(decksProgrammersModel);

    dispatch({
      type: DECKS_LOADED_PUBLIC,
      payload: {
        decksPM: decksProgrammersModel,
      },
    });
  };

type DispatchFunc = () => AppDispatch;
export const useAppDispatch: DispatchFunc = useDispatch;

export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;

export const selectDecks = (state: RootState) => {
  return state.decksState.decksPM;
};

interface Deck {
  id: number;
  userId: number;
  subject: string;
  Tags: string[];
  private: boolean;
  alertInterval: number;
}

interface DecksState {
  decksPM: Deck[] | null;
}

const initialState: DecksState = {
  decksPM: null,
};

const reducer = (decksState = initialState, action: AppAction): DecksState => {
  switch (action.type) {
    case DECKS_LOADED_PUBLIC: {
      return {
        ...decksState,
        decksPM: action.payload.decksPM,
      };
    }
    default: {
      return decksState;
    }
  }
};

export default reducer;
#

DeckPresenter.ts

import { RootState } from "src/core/store";
import * as repository from "./DeckRepository";

export const loadPublicDecks = repository.loadPublicDecks;

export const selectDecks = (state: RootState) => {
  const decksPM = repository.selectDecks(state);

  return decksPM || [];
};

Page component

import { useEffect } from "react";
import * as presenter from "./DeckPresenter";
import { DeckList } from "./DeckList";
import { useAppDispatch, useAppSelector } from "./DeckRepository";

export const DiscoverFlashcardPage = () => {
  const dispatch = useAppDispatch();
  const decksViewModel = useAppSelector(presenter.selectDecks);

  useEffect(() => {
    dispatch(presenter.loadPublicDecks()); // <-- TS warning appears here about dispatch or presenter
  }, [dispatch]);

  return (
    <div>
      <div>Search bar here</div>
      <main>
        <DeckList viewModel={decksViewModel} />
      </main>
    </div>
  );
};
#

The warning I am receiving is:

No overload matches this call.
  Overload 1 of 3, '(thunkAction: ThunkAction<Promise<void>, CombinedState<{ decksState: DecksState; }>, HttpGateway, LoadPublicDeckAction>): Promise<...>', gave the following error.
    Argument of type '(dispatch: AppDispatch, _getState: AppGetState, { http }: { http: HttpGateway; }) => Promise<void>' is not assignable to parameter of type 'ThunkAction<Promise<void>, CombinedState<{ decksState: DecksState; }>, HttpGateway, LoadPublicDeckAction>'.
      Types of parameters '__2' and 'extraArgument' are incompatible.
        Property 'http' is missing in type 'HttpGateway' but required in type '{ http: HttpGateway; }'.
  Overload 2 of 3, '(action: LoadPublicDeckAction): LoadPublicDeckAction', gave the following error.
    Argument of type '(dispatch: AppDispatch, _getState: AppGetState, { http }: { http: HttpGateway; }) => Promise<void>' is not assignable to parameter of type 'LoadPublicDeckAction'.
  Overload 3 of 3, '(action: LoadPublicDeckAction | ThunkAction<Promise<void>, CombinedState<{ decksState: DecksState; }>, HttpGateway, LoadPublicDeckAction>): LoadPublicDeckAction | Promise<...>', gave the following error.
    Argument of type '(dispatch: AppDispatch, _getState: AppGetState, { http }: { http: HttpGateway; }) => Promise<void>' is not assignable to parameter of type 'LoadPublicDeckAction | ThunkAction<Promise<void>, CombinedState<{ decksState: DecksState; }>, HttpGateway, LoadPublicDeckAction>'.
      Type '(dispatch: AppDispatch, _getState: AppGetState, { http }: { http: HttpGateway; }) => Promise<void>' is not assignable to type 'ThunkAction<Promise<void>, CombinedState<{ decksState: DecksState; }>, HttpGateway, LoadPublicDeckAction>'.