Redux Toolkit exports several type-safe action matching utilities that you can leverage when checking for specific kinds of actions. These are primarily useful for the builder.addMatcher() cases in createSlice and createReducer, as well as when writing custom middleware.
General Purpose
isAllOf - returns true when all conditions are met
isAnyOf - returns true when at least one of the conditions are met
createAsyncThunk-specific matchers
All these matchers can either be called with one or more thunks as arguments, in which case they will return a matcher function for that condition and thunks, or with one actions, in which case they will match for any thunk action with said condition.
isAsyncThunkAction - accepts one or more action creators and returns true when all match
isPending - accepts one or more action creators and returns true when all match
isFulfilled - accepts one or more action creators and returns true when all match
isRejected - accepts one or more action creators and returns true when all match
isRejectedWithValue - accepts one or more action creators and returns true when all match
isAllOf
A higher-order function that accepts one or more of:
redux-toolkit action creator functions such as the ones produced by:
custom action creator functions that have a .match property that is a type guard
It will return a type guard function that returns true if all of the provided functions match.
isAnyOf
Accepts the same inputs as isAllOf and will return a type guard function that returns true if at least one of the provided functions match.
isAsyncThunkAction
A higher-order function that returns a type guard function that may be used to check whether an action was created by createAsyncThunk.
import { isAsyncThunkAction, AnyAction } from'@reduxjs/toolkit'import { requestThunk1, requestThunk2 } from'@virtual/matchers'constisARequestAction=isAsyncThunkAction(requestThunk1, requestThunk2)functionhandleRequestAction(action:AnyAction) {if (isARequestAction(action)) {// action is an action dispatched by either `requestThunk1` or `requestThunk2` }}
isPending
A higher-order function that returns a type guard function that may be used to check whether an action is a 'pending' action creator from the createAsyncThunk promise lifecycle.
import { isPending, AnyAction } from'@reduxjs/toolkit'import { requestThunk1, requestThunk2 } from'@virtual/matchers'constisAPendingAction=isPending(requestThunk1, requestThunk2)functionhandlePendingAction(action:AnyAction) {if (isAPendingAction(action)) {// action is a pending action dispatched by either `requestThunk1` or `requestThunk2` }}
isFulfilled
A higher-order function that returns a type guard function that may be used to check whether an action is a 'fulfilled'' action creator from the createAsyncThunk promise lifecycle.
import { isFulfilled, AnyAction } from'@reduxjs/toolkit'import { requestThunk1, requestThunk2 } from'@virtual/matchers'constisAFulfilledAction=isFulfilled(requestThunk1, requestThunk2)functionhandleFulfilledAction(action:AnyAction) {if (isAFulfilledAction(action)) {// action is a fulfilled action dispatched by either `requestThunk1` or `requestThunk2` }}
isRejected
A higher-order function that returns a type guard function that may be used to check whether an action is a 'rejected' action creator from the createAsyncThunk promise lifecycle.
import { isRejected, AnyAction } from'@reduxjs/toolkit'import { requestThunk1, requestThunk2 } from'@virtual/matchers'constisARejectedAction=isRejected(requestThunk1, requestThunk2)functionhandleRejectedAction(action:AnyAction) {if (isARejectedAction(action)) {// action is a rejected action dispatched by either `requestThunk1` or `requestThunk2` }}
isRejectedWithValue
A higher-order function that returns a type guard function that may be used to check whether an action is a 'rejected' action creator from the createAsyncThunk promise lifecycle that was created by rejectWithValue.
import { isRejectedWithValue, AnyAction } from'@reduxjs/toolkit'import { requestThunk1, requestThunk2 } from'@virtual/matchers'constisARejectedWithValueAction=isRejectedWithValue( requestThunk1, requestThunk2)functionhandleRejectedWithValueAction(action:AnyAction) {if (isARejectedWithValueAction(action)) {// action is a rejected action dispatched by either `requestThunk1` or `requestThunk2`// where rejectWithValue was used }}
Using matchers to reduce code complexity, duplication and boilerplate
When using the builder pattern to construct a reducer, we add cases or matchers one at a time. However, by using isAnyOf or isAllOf, we're able to easily use the same matcher for several cases in a type-safe manner.
First, let's examine an unnecessarily complex example:
In this scenario, we can use isAllOf to simplify our code and reduce some of the boilerplate.
import { createReducer, isAllOf } from'@reduxjs/toolkit'import { isSpecialAndInterestingThunk, initialState, isSpecial, isInteresting, Data,} from'@virtual/matchers'// This is a fake pkg that provides the types shown aboveconstloadingReducer=createReducer(initialState, (builder) => { builder.addMatcher(isAllOf(isSpecialAndInterestingThunk.fulfilled, isSpecial), (state, action) => {state.isSpecial =true } ).addMatcher(isAllOf(isSpecialAndInterestingThunk.fulfilled, isInteresting), (state, action) => {state.isInteresting =true } )})
Using matchers as a TypeScript Type Guard
The function returned by isAllOf and isAnyOf can also be used as a TypeScript type guard in other contexts.
import { isAllOf, PayloadAction } from'@reduxjs/toolkit'import { Data, isSpecial, isInteresting } from '@virtual/matchers' // This is a fake pkg that provides the types shown above
constisSpecialAndInteresting=isAllOf(isSpecial, isInteresting)functionsomeFunction(action:PayloadAction<Data>) {if (isSpecialAndInteresting(action)) {// "action" will be correctly typed as:// `PayloadAction<Special> & PayloadAction<Interesting>` }}
import { isAnyOf, PayloadAction } from'@reduxjs/toolkit'import { Data, isSpecial, isInteresting } from '@virtual/matchers' // this is a fake pkg that provides the types shown above
constisSpecialOrInteresting=isAnyOf(isSpecial, isInteresting)functionsomeFunction(action:PayloadAction<Data>) {if (isSpecialOrInteresting(action)) {// "action" will be correctly typed as:// `PayloadAction<Special> | PayloadAction<Interesting>` }}