thSoft
thSoft

Reputation: 22670

How to use AppDispatch type in in Redux async thunk?

In my Redux async thunks, I want to use the AppDispatch type that is inferred as described here: https://redux.js.org/recipes/usage-with-typescript

I followed the instructions here: https://redux.js.org/recipes/usage-with-typescript#typing-createasyncthunk

But when using this AppDispatch type in my custom ThunkApiConfig type (MyThunkApiConfig in the following example), there will be a circular reference as demonstrated here: https://codesandbox.io/s/focused-joliot-ho45h?file=/src/usersSlice.ts:

'dispatch' is referenced directly or indirectly in its own type annotation.

Which makes sense, since there is a circular dependency between the dispatch type and the used thunks. But then how can I use AppDispatch in the async thunk?

Thanks for the answer in advance!

Upvotes: 2

Views: 2150

Answers (1)

Linda Paiste
Linda Paiste

Reputation: 42228

There is no problem with using AppDispatch in your MyThunkApiConfig type. The problem comes about when you do that and also define your slice as a function of the async action. This causes a tight coupling between the slice types and the dispatch type which should not exist.

If the reducer is usersSlice.reducer then there is no problem. This version uses the updateUser aynsc thunk, which in turn uses the typed dispatch. But the type for the slice does not depend on the dispatch type. It is only concerned with the types for the state and the actions that it creates (in this case, none).

Your createAsyncSlice on the other hand uses MyThunkApiConfig in its argument type. So this creates a circle where the store type depends on the slice type and the slice type depends on the store type.

I fundamentally don't get what you are trying to achieve by passing the updateUser aysnc thunk through a function instead of just using it directly. Obviously the easy solution here is "don't do that".


If you wanted to assign the type for AppDispatch directly, you can of course do that. It's not recommended because the types are complex and rely on a lot of generic type parameters.

export type RootState = { users: UsersState }
export type AppDispatch = Dispatch<AnyAction> & ThunkDispatch<RootState, null, AnyAction> 

In your example you don't actually need the MyThunkApiConfig at all. You could just drop the generics from updateUser. They will end up being inferred as <User, void, {}> which is sufficient. You could type your slice argument as asyncThunk: AsyncThunk<User, void, {}> and that would also fix the circular typings.

Upvotes: 3

Related Questions