Usage with TypeScript
Usage > TypeScript: how to correctly type React Redux APIs
Usage with TypeScript
React Redux itself is currently written in plain JavaScript. However, it works well with static type systems such as TypeScript.
The React Redux type definitions are a separate @types/react-redux
typedefs package on NPM. In addition to typing the library functions, the types also export some helpers to make it easier to write typesafe interfaces between your Redux store and your React components.
As of React Redux v7.2.3, the react-redux
package has a dependency on @types/react-redux
, so the type definitions will be automatically installed with the library. Otherwise, you'll need to manually install them yourself ( npm install @types/react-redux
).
Standard Redux Toolkit Project Setup with TypeScript
We assume that a typical Redux project is using Redux Toolkit and React Redux together.
Redux Toolkit (RTK) is the standard approach for writing modern Redux logic. RTK is already written in TypeScript, and its API is designed to provide a good experience for TypeScript usage.
The Redux+TS template for Create-React-App comes with a working example of these patterns already configured.
Define Root State and Dispatch Types
Using configureStore should not need any additional typings. You will, however, want to extract the RootState
type and the Dispatch
type so that they can be referenced as needed. Inferring these types from the store itself means that they correctly update as you add more state slices or modify middleware settings.
Since those are types, it's safe to export them directly from your store setup file such as app/store.ts
and import them directly into other files.
Define Typed Hooks
While it's possible to import the RootState
and AppDispatch
types into each component, it's better to create pre-typed versions of the useDispatch
and useSelector
hooks for usage in your application. This is important for a couple reasons:
For
useSelector
, it saves you the need to type(state: RootState)
every timeFor
useDispatch
, the defaultDispatch
type does not know about thunks or other middleware. In order to correctly dispatch thunks, you need to use the specific customizedAppDispatch
type from the store that includes the thunk middleware types, and use that withuseDispatch
. Adding a pre-typeduseDispatch
hook keeps you from forgetting to importAppDispatch
where it's needed.
Since these are actual variables, not types, it's important to define them in a separate file such as app/hooks.ts
, not the store setup file. This allows you to import them into any component file that needs to use the hooks, and avoids potential circular import dependency issues.
Typing Hooks Manually
We recommend using the pre-typed useAppSelector
and useAppDispatch
hooks shown above. If you prefer not to use those, here is how to type the hooks by themselves.
Typing the useSelector
hook
useSelector
hookWhen writing selector functions for use with useSelector
, you should explicitly define the type of the state
parameter. TS should be able to then infer the return type of the selector, which will be reused as the return type of the useSelector
hook:
This can also be done inline as well:
Typing the useDispatch
hook
useDispatch
hookBy default, the return value of useDispatch
is the standard Dispatch
type defined by the Redux core types, so no declarations are needed:
If you have a customized version of the Dispatch
type, you may use that type explicitly:
Typing the connect
higher order component
connect
higher order componentInferring The Connected Props Automatically
connect
consists of two functions that are called sequentially. The first function accepts mapState
and mapDispatch
as arguments, and returns a second function. The second function accepts the component to be wrapped, and returns a new wrapper component that passes down the props from mapState
and mapDispatch
. Normally, both functions are called together, like connect(mapState, mapDispatch)(MyComponent)
.
As of v7.1.2, the @types/react-redux
package exposes a helper type, ConnectedProps
, that can extract the return types of mapStateToProps
and mapDispatchToProps
from the first function. This means that if you split the connect
call into two steps, all of the "props from Redux" can be inferred automatically without having to write them by hand. While this approach may feel unusual if you've been using React-Redux for a while, it does simplify the type declarations considerably.
The return type of ConnectedProps
can then be used to type your props object.
Because types can be defined in any order, you can still declare your component before declaring the connector if you want.
Manually Typing connect
connect
The connect
higher-order component is somewhat complex to type, because there are 3 sources of props: mapStateToProps
, mapDispatchToProps
, and props passed in from the parent component. Here's a full example of what it looks like to do that manually.
It is also possible to shorten this somewhat, by inferring the types of mapState
and mapDispatch
:
However, inferring the type of mapDispatch
this way will break if it is defined as an object and also refers to thunks.
Recommendations
The hooks API is generally simpler to use with static types. If you're looking for the easiest solution for using static types with React-Redux, use the hooks API.
If you're using connect
, we recommend using the ConnectedProps<T>
approach for inferring the props from Redux, as that requires the fewest explicit type declarations.
Resources
For additional information, see these additional resources:
Redux docs: Usage with TypeScript: Examples of how to use Redux Toolkit, the Redux core, and React Redux with TypeScript
Redux Toolkit docs: TypeScript Quick start: shows how to use RTK and the React-Redux hooks API with TypeScript
React+TypeScript Cheatsheet: a comprehensive guide to using React with TypeScript
React + Redux in TypeScript Guide: extensive information on patterns for using React and Redux with TypeScript
Last updated