1

I'm trying to dispatch an action (don't know if it's the right name, because I'm really new to redux and redux-toolkit) and I'm getting this error:

Argument of type 'AsyncThunkAction<Device, number, { dispatch: Dispatch<AnyAction>; }>' is not assignable to parameter of type 'AnyAction'.
  Property 'type' is missing in type 'AsyncThunkAction<Device, number, { dispatch: Dispatch<AnyAction>; }>' but required in type 'AnyAction'.  TS2345

    18 |     if (hasGetError) push('/');
    19 |     else {
  > 20 |       dispatch(getDeviceById(deviceId));
       |                ^
    21 |     }
    22 |   }, [push, hasGetError, dispatch, deviceId]);
    23 |

Here is my code:

store\index.ts

import { configureStore } from '@reduxjs/toolkit';
import { routerMiddleware } from 'connected-react-router/immutable';
import { createBrowserHistory } from 'history';
import thunkMiddleware from 'redux-thunk';
import createRootReducer from './reducers';

export const history = createBrowserHistory();

export const store = configureStore({
  reducer: createRootReducer(history),
  middleware: [routerMiddleware(history), thunkMiddleware],
});

// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>;

export type AppDispatch = typeof store.dispatch;

features\device\redux\deviceOperations.ts

import { createAsyncThunk } from '@reduxjs/toolkit';
import { AppDispatch } from 'src/store';
import { loaderActions } from '../../../features/loader/redux';
import deviceManager from '../deviceManager';

export const getDeviceById = createAsyncThunk<
  Device,
  number,
  {
    dispatch: AppDispatch;
  }
>('device/GET_DEVICE_BY_ID', async (deviceId: number, thunkApi) => {
  thunkApi.dispatch(loaderActions.start('getDeviceById'));
  try {
    const device = await deviceManager.getDeviceById(deviceId);
    return { ...device, deviceId };
  } finally {
    thunkApi.dispatch(loaderActions.stop('getDeviceById'));
  }
});

interface Device {
  deviceId: number;
  name: string;
}

The part that is causing this error seems to be a custom hook (I'm following another project, but I don't really understand why I need this custom hook and how to use it in my component, I'm really following the example).

features\device\hooks\useGetDeviceById.ts

import { useEffect } from 'react';
import { useHistory, useParams } from 'react-router-dom';
import { useAppDispatch, useAppSelector } from 'src/hooks';
import { fetchStatus } from 'src/shared/constants';
import { getDeviceById } from 'src/features/device/redux/deviceOperations';
import {
  getDevice,
  getDeviceFetchError,
} from 'src/features/device/redux/deviceSelectors';

const useGetDeviceById = () => {
  const dispatch = useAppDispatch();
  const { push } = useHistory();
  const { deviceId } = useParams<{ deviceId?: string }>();

  const device = useAppSelector(getDevice);
  const hasGetError = useAppSelector(getDeviceFetchError);
  const isDeviceLoading =
    device.fetchStatus.getProposalById !== fetchStatus.fulfilled;

  useEffect(() => {
    if (hasGetError) push('/');
    else {
      dispatch(getDeviceById(deviceId)); // ERROR
    }
  }, [push, hasGetError, dispatch, deviceId]);

  return { device: { ...device, deviceId }, isDeviceLoading };
};

export default useGetDeviceById;

How can I fix it? And if I'm not asking much, why would I really need this custom hook?

juliano.net
  • 7,982
  • 13
  • 70
  • 164

1 Answers1

3

The issue you are running into is because you are overriding the middleware that redux-toolkit usually applies which sets up the type definitions properly.

You can fix the issue using getDefaultMiddleware which will allow you to concat on the connected router middleware without ruining the setup.

import { configureStore } from "@reduxjs/toolkit";
import { routerMiddleware } from "connected-react-router/immutable";
import { createBrowserHistory } from "history";
import createRootReducer from "./reducers";

export const history = createBrowserHistory();

export const store = configureStore({
  reducer: createRootReducer(history),
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(routerMiddleware(history))
});

// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>;

export type AppDispatch = typeof store.dispatch;

Here's an approximation of the code (enough at least for those type errors to show/be fixed):

https://codesandbox.io/s/strange-taussig-oweoj?file=/src/useGetDeviceById.ts

Zachary Haber
  • 10,376
  • 1
  • 17
  • 31