Redux-toolkit: how to infer type of rejectWithValue

Created on 19 May 2021  路  5Comments  路  Source: reduxjs/redux-toolkit

I commented this on a closed issue here, but wasn't sure if the github notifications would notify of that comment (since I couldn't see it in my history anywhere).

Anyway, here's my question.

How do I infer the type for rejectWithValue?

Neither AppThunkDispatch, AppThunk or AppDispatch seem to be doing the trick here. I've also tried RejectedWithValueActionFromAsyncThunk and RejectedActionFromAsyncThunk, but those aren't accepted either.

Am I missing something? I thought rejectWithValue dispatched an action just like AppThunkDispatch ?

export type RootState = ReturnType<typeof store.getState>;

export type AppDispatch = typeof store.dispatch;

export type AppThunk<ReturnType = void> = ThunkAction<
  ReturnType,
  RootState,
  unknown,
  AnyAction
>;

export type AppThunkDispatch = ThunkDispatch<void, RootState, AnyAction>;

const initializeApplication = createAsyncThunk<
  AppThunkDispatch,
  null,
  { state: RootState; rejectValue: IAuthErrorResponse }
>(
  "app/initializeApplication",
  async (
    _,
    {
      dispatch,
      rejectWithValue,
    }: { 
      dispatch: AppDispatch; 
      rejectWithValue: any // <-- Too open, but other types such as
                           // RejectedActionFromAsyncThunk or RejectedWithValueActionFromAsyncThunk 
                           // extend AnyAction and I couldn't find an appropriate way to type this. 
                           // Isn't this a dispatch call?
   }
  ) => {
    try {
      const mappedUser = await authApi.fetchCurrentUserDetails();

      return dispatch(userActions.setUser(mappedUser));
    } catch (error) {
      const responseData: IAuthErrorResponse = {
        statusCode: error.status,
        error: error.statusText,
        message: "Invalid Token",
      };

      return rejectWithValue(responseData);
    }
  }
);

Most helpful comment

Generally, I would consider that eslint rule as actually detrimental to your code. noImplicitAny should be enough to enforce type annotations where the compiler is not able to infer them - and in places where it can infer them, declaring those manually can only make already-known types more inaccurate.

All 5 comments

This is not a dispatch call. Use something like string, number, Error or whatever there.
It will end up in an action later.

using anything other than any or unknown causes TS to complain. For example, if use string:

TS2345: Argument of type '(_: null, { dispatch, rejectWithValue, }: { dispatch: ThunkDispatch<EmptyObject & IRootState, null, AnyAction> & ThunkDispatch<EmptyObject & IRootState, undefined, AnyAction> & Dispatch<...>; rejectWithValue: string; }) => Promise<...>' is not assignable to parameter of type 'AsyncThunkPayloadCreator<AppThunkDispatch, null, { state: EmptyObject & IRootState; rejectValue: IAuthErrorResponse; }>'. 聽聽Types of parameters '__1' and 'thunkAPI' are incompatible. 聽聽聽聽Type 'GetThunkAPI<{ state: EmptyObject & IRootState; rejectValue: IAuthErrorResponse; }>' is not assignable to type '{ dispatch: ThunkDispatch<EmptyObject & IRootState, null, AnyAction> & ThunkDispatch<EmptyObject & IRootState, undefined, AnyAction> & Dispatch<...>; rejectWithValue: string; }'. 聽聽聽聽聽聽Types of property 'rejectWithValue' are incompatible. 聽聽聽聽聽聽聽聽Type '(value: IAuthErrorResponse) => RejectWithValue<IAuthErrorResponse>' is not assignable to type 'string'

I think the interesting bit is 聽Type '(value: IAuthErrorResponse) => RejectWithValue<IAuthErrorResponse>' is not assignable to type 'string'

I also tried typing it to

...
rejectWithValue: (value: IAuthErrorResponse) => RejectWithValue<IAuthErrorResponse>;
...

but unfortunately RejectWithValue doesn't work either.

Is this meant to be unknown or am I missing something?

Uhhh, just seeing this: Don't type your thunkApi function argument, that is already fully typed by you declaring the generic arguments.

ok, I'll have to exclude it from my eslint file then. I'm not sure how to go about that but if I find a solution I'll post it here. Closing now.

Generally, I would consider that eslint rule as actually detrimental to your code. noImplicitAny should be enough to enforce type annotations where the compiler is not able to infer them - and in places where it can infer them, declaring those manually can only make already-known types more inaccurate.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

will-amaral picture will-amaral  路  3Comments

ouweiya picture ouweiya  路  3Comments

Izhaki picture Izhaki  路  3Comments

SoYoung210 picture SoYoung210  路  4Comments

amankkg picture amankkg  路  4Comments