Is there a way to pass a generic type to the reducer used in react useReducer hook?

Viewed 854

I'm trying to implement a React custom hook for data fetching using this article. This custom hook looks like this

type Action<T> =
    | { type: "FETCH_INIT" }
    | { payload: T; type: "FETCH_SUCCESS" }
    | { error: string; type: "FETCH_FAILURE" };

interface IState<T> {
    data: T;
    error: string;
    isLoading: boolean;
}

export const useFetch = <T>(initialUrl: string, initialData: T) => {

    const initialState = {
        data: initialData,
        error: "",
        isLoading: false,
    };


    const [state, dispatch] = useReducer<Reducer<IState<T>, Action<T>>>(dataFetchReducer, initialState);
    ...
};

Problem

The problem is when I try to type the dataFetchReducer function. I'm not sure how to pass the generic type from useFetch to dataFetchReducer.

Here is what dataFetchReducer currently looks like.

const dataFetchReducer = <T>(state: IState<T>, action: Action<T>): IState<T> => {...};

I might be overthinking it and React actually pass the generic type from useReducer to dataFetchReducer but I'm not sure and I don't even how to test this behaviour.

1 Answers

What about this:

export const reducer: <
    TS extends IEntityState<IEntity>,
    T extends IEntity
>(initialEntity: T) => React.Reducer<TS, Actions> = (initialEntity) => {
    return (state, action) =>  {
        switch(action.type) {
            case ActionTypes.GET_ALL:
                return {
                    ...state,
                    entites: action.entites,
                }
            // ...
        }
    }
}

and then:

const [state, dispatch] = useReducer<React.Reducer<IStudentState, Actions>>
        (reducer<IStudentState, IStudent>(initialStudent), initialState);
Related