Alan Schapira
Alan Schapira

Reputation: 1163

Redux action return type when using dispatch and getState

I am struggling to figure out what the return type should be for my action. Everything works whilst I am using any but am trying to avoid using any.

export const saveValue = (value: number): any => {
    return (dispatch: Dispatch<SaveValue>, getState: () => State): void => {
        axios.post('www.exampleurl.com', value)
            .then((response) => {
                const someValueFromState = getState().stateValue;
                const payload = {...response, someValueFromState}
                dispatch({ type: constants.SAVE_VALUE, payload });
            });
    };
};

I had it working before when the action was not using getState() and it looked like this, where it returned Dispatch<SaveValue>:

export const saveValue = (value: number): Dispatch<SaveValue> => {
    return (dispatch: Dispatch<SaveValue>): void => {
        axios.post('www.exampleurl.com', value)
            .then((response) => {
                dispatch({ type: constants.SAVE_VALUE, response });
            });
    };
};

But once I added getState, I am not sure what to do anymore. I have tried to put the return value in a variable and can see the object I am creating is const myAttempt: (dispatch: Dispatch<SaveValue>, getState: () => State) => void but when I tried to use it as follows, it doesn't work:

export const saveValue = (value: number): (dispatch: Dispatch<SaveValue>, getState: () => StoreState) => void => {
    return (dispatch: Dispatch<SaveValue>, getState: () => State): void => {
        axios.post('www.exampleurl.com', value)
            .then((response) => {
                const someValueFromState = getState().stateValue;
                const payload = {...response, someValueFromState}
                dispatch({ type: constants.SAVE_VALUE, payload });
            });
    };
};

Doing this, I get an error: A function whose declared type is neither 'void' nor 'any' must return a value.

EDIT:

Just to add, I cannot return Dispatch<SaveValue> as I was before, otherwise I get this error: Type '(dispatch: Dispatch<SaveValue>, getState: () => State) => void' is not assignable to type 'Dispatch<SaveValue>'

Upvotes: 5

Views: 15550

Answers (2)

Alan Astorga
Alan Astorga

Reputation: 51

First configure the following in your store:

// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch

then, in your function use the previously custom types

export const getUserRolUid = () => {
    return async (dispatch: AppDispatch, getState: ()=> RootState) => {

      const { uid } = getState().auth;
      const user = await loadUser(uid);
      
      if (user) {
        // update the role and send the data to redux
        dispatch(getUser(user));
      } else {
        dispatch(getUserRolUid());
      }
    };
  }

Upvotes: 5

Alan Schapira
Alan Schapira

Reputation: 1163

A friend helped me answer this. This was the right way to do it:

export const saveValue = (value: number): (dispatch: Dispatch<SaveValue>, getState: () => State): void => {
    return (dispatch: Dispatch<SaveValue>, getState: () => State): void => {
        axios.post('www.exampleurl.com', value)
            .then((response) => {
                const someValueFromState = getState().stateValue;
                const payload = {...response, someValueFromState}
                dispatch({ type: constants.SAVE_VALUE, payload });
            });
    };
};

The issue I was having was with my mapDispatchToProps function which was being explicitly typed and causing the error Type '(dispatch: Dispatch<SaveVisit>, getState: () => StoreState) => void' is not assignable to type 'Dispatch<SaveVisit>'. The function was:

interface MapDispatchToPropsInterface {
    saveValue : (value: number) => Dispatch<SaveValue>;
}

const mapDispatchToProps: MapDispatchToPropsInterface = {
    saveValue : ActionCreators.saveValue,
};

but the interface needed to be:

interface MapDispatchToPropsInterface {
    saveValue : (saveDetails: CheckedVisit) =>  (dispatch: Dispatch<SaveValue>, getState: () => StoreState) => void;
}

Upvotes: 9

Related Questions