What You'll Learn
- Details on how to use each Redux Toolkit API with TypeScript
Redux Toolkit is written in TypeScript, and its API is designed to enable great integration with TypeScript applications.
This page provides specific details for each of the different APIs included in Redux Toolkit and how to type them correctly with TypeScript.
See the TypeScript Quick Start tutorial page for a brief overview of how to set up and use Redux Toolkit and React Redux to work with TypeScript.
If you encounter any problems with the types that are not described on this page, please open an issue for discussion.
The basics of using
configureStore are shown in TypeScript Quick Start tutorial page. Here are some additional details that you might find useful.
The easiest way of getting the
State type is to define the root reducer in advance and extract its
It is recommend to give the type a different name like
RootState to prevent confusion, as the type name
State is usually overused.
Alternatively, if you choose to not create a
rootReducer yourself and instead pass the slice reducers directly to
configureStore(), you need to slightly modify the typing to correctly infer the root reducer:
If you want to get the
Dispatch type from your store, you can extract it after creating the store. It is recommended to give the type a different name like
AppDispatch to prevent confusion, as the type name
Dispatch is usually overused. You may also find it to be more convenient to export a hook like
useAppDispatch shown below, then using it wherever you'd call
Correct typings for the
The type of the
dispatch function type will be directly inferred from the
middleware option. So if you add correctly typed middlewares,
dispatch should already be correctly typed.
As TypeScript often widens array types when combining arrays using the spread operator, we suggest using the
.prepend(...) methods of the
MiddlewareArray returned by
Also, we suggest using the callback notation for the
middleware option to get a correctly pre-typed version of
getDefaultMiddleware that does not require you to specify any generics by hand.
If you want to skip the usage of
getDefaultMiddleware altogether, you can still use
MiddlewareArray for type-safe concatenation of your
Array type, only with modified typings for
.concat(...) and the additional
This is generally not required though, as you will probably not run into any array-type-widening issues as long as you are using
as const and do not use the spread operator.
So the following two calls would be equivalent:
Using the extracted
Dispatch type with React Redux#
By default, the React Redux
useDispatch hook does not contain any types that take middlewares into account. If you need a more specific type for the
dispatch function when dispatching, you may specify the type of the returned
dispatch function, or create a custom-typed version of
useSelector. See the React Redux documentation for details.
For most use cases, there is no need to have a literal definition of
action.type, so the following can be used:
This will result in the created action being of type
In some setups, you will need a literal type for
Unfortunately, TypeScript type definitions do not allow for a mix of manually-defined and inferred type parameters, so you'll have to specify the
If you are looking for an alternate way of writing this without the duplication, you can use a prepare callback so that both type parameters can be inferred from arguments, removing the need to specify the action type.
Alternative to using a literally-typed
If you are using
action.type as a discriminator on a discriminated union, for example to correctly type your payload in
case statements, you might be interested in this alternative:
Created action creators have a
match method that acts as a type predicate:
match method is also very useful in combination with
redux-observable and RxJS's
The default way of calling
createReducer would be with a "lookup table" / "map object", like this:
Unfortunately, as the keys are only strings, using that API TypeScript can neither infer nor validate the action types for you:
As an alternative, RTK includes a type-safe reducer builder API.
Instead of using a simple object as an argument to
createReducer, you can also use a callback that receives a
We recommend using this API if stricter type safety is necessary when defining reducer argument objects.
As the first
matcher argument to
builder.addMatcher, a type predicate function should be used.
As a result, the
action argument for the second
reducer argument can be inferred by TypeScript:
createSlice creates your actions as well as your reducer for you, you don't have to worry about type safety here.
Action types can just be provided inline:
If you have too many case reducers and defining them inline would be messy, or you want to reuse case reducers across slices, you can also define them outside the
createSlice call and type them as
You might have noticed that it is not a good idea to pass your
SliceState type as a generic to
createSlice. This is due to the fact that in almost all cases, follow-up generic parameters to
createSlice need to be inferred, and TypeScript cannot mix explicit declaration and inference of generic types within the same "generic block".
The standard approach is to declare an interface or type for your state, create an initial state value that uses that type, and pass the initial state value to
createSlice. You can also use the construct
initialState: myInitialState as SliceState.
which will result in a
Defining Action Contents with
If you want to add a
error property to your action, or customize the
payload of your action, you have to use the
Using this notation with TypeScript looks like this:
As TS cannot combine two string literals (
slice.name and the key of
actionMap) into a new literal, all actionCreators created by
createSlice are of type 'string'. This is usually not a problem, as these types are only rarely used as literals.
In most cases that
type would be required as a literal, the
slice.action.myAction.match type predicate should be a viable alternative:
If you actually need that type, unfortunately there is no other way than manual casting.
Type safety with
Reducer lookup tables that map an action
type string to a reducer function are not easy to fully type correctly. This affects both
createReducer and the
extraReducers argument for
createSlice. So, like with
createReducer, you may also use the "builder callback" approach for defining the reducer object argument.
This is particularly useful when a slice reducer needs to handle action types generated by other slices, or generated by specific calls to
createAction (such as the actions generated by
builder also accepts
addMatcher (see typing
If you need to reuse reducer logic, it is common to write "higher-order reducers" that wrap a reducer function with additional common behavior. This can be done with
createSlice as well, but due to the complexity of the types for
createSlice, you have to use the
ValidateSliceCaseReducers types in a very specific way.
Here is an example of such a "generic" wrapped
In the most common use cases, you should not need to explicitly declare any types for the
createAsyncThunk call itself.
Just provide a type for the first argument to the
payloadCreator argument as you would for any function argument, and the resulting thunk will accept the same type as its input parameter.
The return type of the
payloadCreator will also be reflected in all generated action types.
The second argument to the
payloadCreator, known as
thunkApi, is an object containing references to the
extra arguments from the thunk middleware as well as a utility function called
rejectWithValue. If you want to use these from within the
payloadCreator, you will need to define some generic arguments, as the types for these arguments cannot be inferred. Also, as TS cannot mix explicit and inferred generic parameters, from this point on you'll have to define the
ThunkArg generic parameter as well.
To define the types for these arguments, pass an object as the third generic argument, with type declarations for some or all of these fields:
If you are performing a request that you know will typically either be a success or have an expected error format, you can pass in a type to
return rejectWithValue(knownPayload) in the action creator. This allows you to reference the error payload in the reducer as well as in a component after dispatching the
While this notation for
rejectValue might seem uncommon at first, it allows you to provide only the types for these you actually need - so for example, if you are not accessing
getState within your
payloadCreator, there is no need to provide a type for
state. The same can be said about
rejectValue - if you don't need to access any potential error payload, you can ignore it.
In addition, you can leverage checks against
match as provided by
createAction as a type-guard for when you want to access known properties on defined types. Example:
- In a reducer
- In a component
createEntityAdapter only requires you to specify the entity type as the single generic argument.
The example from the
createEntityAdapter documentation would look like this in TypeScript:
When using a library like
normalizr, your normalized data will resemble this shape:
setAll all allow you to pass in the
entities portion of this directly with no extra conversion steps. However, the
normalizr TS typings currently do not correctly reflect that multiple data types may be included in the results, so you will need to specify that type structure yourself.
Here is an example of how that would look: