Adil Akhmetov
Adil Akhmetov

Reputation: 121

Argument of type '(dispatch: Dispatch) => void' is not assignable to parameter of type 'AnyAction'

The error itself:

(alias) deleteCategory(id: number): (dispatch: Dispatch<AnyAction>) => void
import deleteCategory
Argument of type '(dispatch: Dispatch) => void' is not assignable to parameter of type 'AnyAction'.
  Property 'type' is missing in type '(dispatch: Dispatch) => void' but required in type 'AnyAction'.ts(2345)

Problematic code:

export function getCategoryList(
  categories: CategoryType[],
  dispatch: Dispatch
) {
  return categories.map((category: CategoryType) => ({
    ...category,
    onDelete: () => {
      dispatch(deleteCategory(category._id)); //FIXME: Fix this. Error Appears here
    },
  }));
}

Implementation of deleteCategory:

export const deleteCategory = (id: number) => (dispatch: Dispatch) => {
  deleteCategoryAPI(id)
    .then(() => {
      dispatch({
        type: DELETE_CATEGORY,
        category: id,
      });
    })
    .catch((error) => console.error(error));
};

Implementation of deleteCategoryAPI:

export async function addCategoryAPI(category: CategoryType) {
  return fetch(`${API_URL}/categories`, {
    method: "POST",
    body: JSON.stringify(category),
    headers: { "Content-Type": "application/json; charset=UTF-8" },
  }).then((response) => response.json());
}

I am using problematic code here:

const categoryList = getCategoryList(categoryState, dispatch);
...
return (
    <List
      dataSource={categoryList}
      renderItem={({ name, onDelete }) => (
        <List.Item>
          <CategoryItem name={name} onDelete={onDelete} />
        </List.Item>
      )}
    />
  );
function CategoryItem({ name, onDelete }: categoryItemPropsType) {
export type categoryItemPropsType = {
  name: string;
  onDelete: () => void;
};

What could be a problem? Spent several hours for that. The interesting thing is that when I call dispatch(deleteCategory(category._id)) somewhere else in functional component e.g. it works without any problems.. Thank you very much!

Upvotes: 11

Views: 19633

Answers (1)

flycrum
flycrum

Reputation: 111

I can initially think of a few different ways you could consider going about this depending on how much effort you feel like putting into it, how true to the vanilla implementation you'd like, and how accurate of typings you want.

  1. The easiest implementation and truest to the API (but with poor typings):

    // create your own dispatch function reference with custom typings
    export const dispatchStore = store.dispatch as typeof store.dispatch | Dispatch<any>
    
    // use custom typed dispatch (unfortunately, you can pass it almost `any`thing)
    dispatchStore(myThunk('id123'))
    
  2. An easy implementation but requires typing each call (and still has poor typings):

    // optional
    export const dispatchStore = store.dispatch
    
    // type each dispatch as any (not good if you need to use 'abort', etc)
    dispatchStore(myThunk('id123') as any)
    
  3. This bullet is specific to Redux Toolkit but could easily apply to most TypeScript typing issues with third-party libraries (e.g. Redux). In the case of using redux-toolkit, one could create a reference to either configureStore or createSlice and manipulate the typings as you choose. In the following code, I wrapped the createSlice function in createSlicePlus, added a bunch of convenience logic behind the scenes, and enhanced the args and return types.

    // convenience `request` wrapper around store `dispatch` that abstracts the rest
    const promise = counter.request.decrementThunk(500)
    // even the RTK thunk promise is typed appropriately
    promise.abort()
    

The code for 3rd example can be found here on Github.

Upvotes: 5

Related Questions