0
votes

I have created simple react App during learning middleware redux-thunk. I have a problem with transpilation because of incorrect type of async action fetchPosts in interface PostListProps.

Below I show all code of the functional component where is the problem:

import React, { useEffect } from 'react'
import { connect } from 'react-redux'
import { fetchPosts } from '../actions'
import Action from '../actions/actionTypes'
import { Dispatch } from "react";
import State from '../reducers/State'

interface PostListProps { 
    fetchPosts: () => (dispatch: Dispatch<Action>) => Promise<void>
}

const PostList = (props: PostListProps) => {
    useEffect(() => {
        props.fetchPosts()
    }, [])
    return (
        <div>Post List</div>
    )
}

const mapStateToProps = (state: State) => {
    return { posts: state.posts };
};

export default connect(
    mapStateToProps,
    { fetchPosts }
)(PostList);

My code is transpiled without error only when I change type of fetchPosts function to:

fetchPosts: () => any

Below I present code of function fetchPosts:

import Action, { ActionType } from "./actionTypes";
import jsonPlaceholder from "../apis/jsonPlaceholder";
import { Dispatch } from "react";
import Post from '../apis/Post'
import State from "../reducers/State";
import { AxiosResponse } from "axios";

export const fetchPosts = () => {
    return async (dispatch: Dispatch<Action>) => {
        const response: AxiosResponse<Post[]> = await jsonPlaceholder.get<Post[]>('/posts')
        dispatch({type: ActionType.FETCH_POSTS, payload: response.data });
    }
}

The error is like below: enter image description here

I have no idea where can be a problem? Why my type of fetchPosts() is wrong? I would like to find out. I would be grateful for help.

1

1 Answers

1
votes

Your component is not concerned with the details of how the posts get fetched and dispatched to the store, so the dispatch bit doesn't need to be reflected in the interface. All the needed wiring is handled by react-redux.

Try this:

interface PostListProps {
    fetchPosts: () => void;
}

Notice that Promise is not mentioned in the interface as your component doesn't await it anyway.

As to how to correctly type the dispatch function, we could infer the proper type from the store instance:

import thunk, { ThunkMiddleware } from 'redux-thunk';

interface AppState {
    posts: PostsState;
    claims: ClaimsState;
}

type AppAction = PostsAction | ClaimsAction;

type AppThunk = ThunkMiddleware<AppState, AppAction>;

const reducer: Reducer<AppState, AppAction> = combineReducers({
  posts: postsReducer,
  claims: claimsReducer,
});

const store = createStore(
    reducer,
    applyMiddleware(thunk as AppThunk)
);

// the type is inferred as
// Dispatch<AppAction> & ThunkDispatch<AppState, undefined, AppAction>
type AppDispatch = typeof store.dispatch;

Slice-specific state and action types would be defined in corresponding slices, something like this:

// posts slice
export type PostsState = Post[];
export type PostsAction =
    | FetchPostsAction
    | FetchPostsFulfilledAction
    | FetchPostsRejectedAction;

// claims slice
export type ClaimsState = Claim[];
export type ClaimsAction =
    | CreateClaimsAction;

You might also want to take a look at the redux-toolkit package, where much of these has been taken care of.