DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 966,904 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Igor Popov
Igor Popov

Posted on

Typescript for Redux Toolkit Slice

The problem: Async action creator with TypeScript source code of example.

The Redux Toolkit is a great library for working with Redux. It allows us to solve the complexity of configuring the Redux store and reduce the amount of boilerplate code for building applications using Redux.
The Immer is used under the hood to facilitate reducers implementation. This saves us from having to control data mutations.
To implement asynchrony, the Redux Toolkit uses Redux Thunk.

TL;DR

Typing of Redux Toolkit async action creator is the most unobvious and difficult to understand part of Redux Toolkit.

This case should allow us to control arguments and return value. Here I describe each parameter for createAsyncThunk typing.

export const incrementAsync = createAsyncThunk<
  // Return type of the payload creator
  number,
  // First argument to the payload creator
  number,
  {
    // Optional fields for defining thunkApi field types
    rejectValue: string
  }
>('counter/fetchCount', async (amount, thunkApi) => {
  const response = await fetchCount(amount)
  if (response.data !== 5) {
    // The value we return becomes the `fulfilled` action payload
    return response.data
  } else {
    // For example we can return validation result here
    return thunkApi.rejectWithValue('Validation error! Response data was 5!')
  }
})
Enter fullscreen mode Exit fullscreen mode

First type number is the return type of the payload creator.
Second type number is the first argument that will be passed to the payload creator. It is our amount value.
Third type is optional fields for defining thunkApi field types.

For this definition of async action creator we can handle returned value or error.

export const counterSlice = createSlice({
  extraReducers: builder => {
    builder
      .addCase(incrementAsync.pending, state => {
        state.status = counterStatus.pending
        state.error = ''
      })
      .addCase(incrementAsync.fulfilled, (state, action) => {
        state.status = counterStatus.idle
        state.value += action.payload
        state.error = ''
      })
      // some error occurred while loading repository content
      .addCase(incrementAsync.rejected, (state, action) => {
        state.status = counterStatus.failed
        if (action.payload) {
          // For example this could be validation error handling
          state.error = action?.payload
        } else {
          state.error = action.error.message
        }
      })
  }
})
Enter fullscreen mode Exit fullscreen mode

Payload creator for async Slice can provide some error with described type string. It was declared for rejectValue of createAsyncThunk typing. Using this sentence with Redux Toolkit automatically coerces the reducer part of the action payload type.

TL;DR

Summary:
This generic type allows us to use the type of our argument. The type of arguments passed is commented as First argument to payload creator.
In my case it’s a β€œnumber” but it can be anything. E.g. object, string, boolean etc. :

createAsyncThunk<
  // Return type of the payload creator
  number,
  // First argument to the payload creator
  number,
  {
    // Optional fields for defining thunkApi field types
    rejectValue: string
  }
>
Enter fullscreen mode Exit fullscreen mode

Top comments (0)

🌚 Friends don't let friends browse without dark mode.

Sorry, it's true.