0
# TypeScript Integration
1
2
React Redux provides comprehensive TypeScript support with full type safety, pre-typed hooks, and extensive type definitions for all API surfaces.
3
4
## Capabilities
5
6
### Pre-typed Hooks (.withTypes() Methods)
7
8
React Redux 9.1.0+ introduces .withTypes() methods for creating pre-typed hooks, eliminating the need to type state and dispatch on every usage.
9
10
```typescript { .api }
11
/**
12
* Creates a pre-typed useSelector hook
13
* @returns UseSelector hook bound to specific state type
14
*/
15
interface UseSelector<StateType = unknown> {
16
withTypes: <OverrideStateType extends StateType>() => UseSelector<OverrideStateType>;
17
}
18
19
/**
20
* Creates a pre-typed useDispatch hook
21
* @returns UseDispatch hook bound to specific dispatch type
22
*/
23
interface UseDispatch<DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>> {
24
withTypes: <OverrideDispatchType extends DispatchType>() => UseDispatch<OverrideDispatchType>;
25
}
26
27
/**
28
* Creates a pre-typed useStore hook
29
* @returns UseStore hook bound to specific store type
30
*/
31
interface UseStore<StoreType extends Store> {
32
withTypes: <OverrideStoreType extends StoreType>() => UseStore<OverrideStoreType>;
33
}
34
```
35
36
**Setup and Usage:**
37
38
```typescript
39
import { useSelector, useDispatch, useStore } from "react-redux";
40
import type { RootState, AppDispatch, AppStore } from "./store";
41
42
// Create pre-typed hooks
43
export const useAppSelector = useSelector.withTypes<RootState>();
44
export const useAppDispatch = useDispatch.withTypes<AppDispatch>();
45
export const useAppStore = useStore.withTypes<AppStore>();
46
47
// Use throughout your app with full type safety
48
function TodoComponent() {
49
// state parameter is automatically typed as RootState
50
const todos = useAppSelector((state) => state.todos);
51
52
// dispatch is automatically typed as AppDispatch (with thunk support)
53
const dispatch = useAppDispatch();
54
55
// store is automatically typed as AppStore
56
const store = useAppStore();
57
58
return <div>{todos.length} todos</div>;
59
}
60
```
61
62
### Typed Hook Interface
63
64
Legacy typed hook interface for pre-9.1.0 versions or alternative typing approaches.
65
66
```typescript { .api }
67
/**
68
* Legacy interface for typed useSelector hook
69
*/
70
interface TypedUseSelectorHook<TState> {
71
<TSelected>(
72
selector: (state: TState) => TSelected,
73
equalityFn?: EqualityFn<NoInfer<TSelected>>
74
): TSelected;
75
<Selected = unknown>(
76
selector: (state: TState) => Selected,
77
options?: UseSelectorOptions<Selected>
78
): Selected;
79
}
80
81
type NoInfer<T> = [T][T extends any ? 0 : never];
82
```
83
84
**Legacy Usage:**
85
86
```typescript
87
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
88
import type { RootState, AppDispatch } from "./store";
89
90
// Create typed hooks (legacy approach)
91
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
92
export const useAppDispatch = () => useDispatch<AppDispatch>();
93
```
94
95
### Store Type Configuration
96
97
Define your store types for use with pre-typed hooks.
98
99
```typescript
100
import { configureStore } from "@reduxjs/toolkit";
101
import { useDispatch, useSelector, useStore } from "react-redux";
102
103
const store = configureStore({
104
reducer: {
105
todos: todosReducer,
106
user: userReducer
107
}
108
});
109
110
// Infer types from store
111
export type RootState = ReturnType<typeof store.getState>;
112
export type AppDispatch = typeof store.dispatch;
113
export type AppStore = typeof store;
114
115
// Create pre-typed hooks
116
export const useAppSelector = useSelector.withTypes<RootState>();
117
export const useAppDispatch = useDispatch.withTypes<AppDispatch>();
118
export const useAppStore = useStore.withTypes<AppStore>();
119
```
120
121
### Component Type Definitions
122
123
Type definitions for React Redux component integration.
124
125
```typescript { .api }
126
/**
127
* Props interface that includes dispatch function
128
*/
129
interface DispatchProp<A extends Action<string> = UnknownAction> {
130
dispatch: Dispatch<A>;
131
}
132
133
/**
134
* Component enhancer type for connect HOC
135
*/
136
type InferableComponentEnhancer<TInjectedProps> =
137
InferableComponentEnhancerWithProps<TInjectedProps, {}>;
138
139
type InferableComponentEnhancerWithProps<TInjectedProps, TNeedsProps> =
140
<C extends ComponentType<Matching<TInjectedProps, GetProps<C>>>>(
141
component: C
142
) => ConnectedComponent<C, Mapped<DistributiveOmit<GetLibraryManagedProps<C>, keyof Shared<TInjectedProps, GetLibraryManagedProps<C>>> & TNeedsProps & ConnectPropsMaybeWithoutContext<TNeedsProps & GetProps<C>>>>;
143
144
/**
145
* Connected component type with original component reference
146
*/
147
type ConnectedComponent<C extends ComponentType<any>, P> =
148
FunctionComponent<P> & NonReactStatics<C> & { WrappedComponent: C };
149
150
/**
151
* Props type inference from connected component
152
*/
153
type ConnectedProps<TConnector> = TConnector extends InferableComponentEnhancerWithProps<infer TInjectedProps, any>
154
? unknown extends TInjectedProps
155
? TConnector extends InferableComponentEnhancer<infer TInjectedProps>
156
? TInjectedProps
157
: never
158
: TInjectedProps
159
: never;
160
```
161
162
### Selector and Dispatch Type Definitions
163
164
Comprehensive type definitions for connect HOC mapping functions.
165
166
```typescript { .api }
167
/**
168
* Selector function types for connect
169
*/
170
type Selector<S, TProps, TOwnProps = null> = TOwnProps extends null | undefined
171
? (state: S) => TProps
172
: (state: S, ownProps: TOwnProps) => TProps;
173
174
type SelectorFactory<S, TProps, TOwnProps, TFactoryOptions> =
175
(dispatch: Dispatch<Action<string>>, factoryOptions: TFactoryOptions) => Selector<S, TProps, TOwnProps>;
176
177
/**
178
* State mapping function types
179
*/
180
type MapStateToProps<TStateProps, TOwnProps, State> =
181
(state: State, ownProps: TOwnProps) => TStateProps;
182
183
type MapStateToPropsFactory<TStateProps, TOwnProps, State> =
184
(initialState: State, ownProps: TOwnProps) => MapStateToProps<TStateProps, TOwnProps, State>;
185
186
type MapStateToPropsParam<TStateProps, TOwnProps, State> =
187
MapStateToPropsFactory<TStateProps, TOwnProps, State> |
188
MapStateToProps<TStateProps, TOwnProps, State> |
189
null |
190
undefined;
191
192
/**
193
* Dispatch mapping function types
194
*/
195
type MapDispatchToPropsFunction<TDispatchProps, TOwnProps> =
196
(dispatch: Dispatch<Action<string>>, ownProps: TOwnProps) => TDispatchProps;
197
198
type MapDispatchToProps<TDispatchProps, TOwnProps> =
199
MapDispatchToPropsFunction<TDispatchProps, TOwnProps> | TDispatchProps;
200
201
type MapDispatchToPropsFactory<TDispatchProps, TOwnProps> =
202
(dispatch: Dispatch<Action<string>>, ownProps: TOwnProps) => MapDispatchToPropsFunction<TDispatchProps, TOwnProps>;
203
204
type MapDispatchToPropsParam<TDispatchProps, TOwnProps> =
205
MapDispatchToPropsFactory<TDispatchProps, TOwnProps> |
206
MapDispatchToProps<TDispatchProps, TOwnProps>;
207
208
/**
209
* Thunk action creator type resolution
210
*/
211
type ResolveThunks<TDispatchProps> = TDispatchProps extends { [key: string]: any }
212
? { [C in keyof TDispatchProps]: HandleThunkActionCreator<TDispatchProps[C]> }
213
: TDispatchProps;
214
215
/**
216
* Props merging function type
217
*/
218
type MergeProps<TStateProps, TDispatchProps, TOwnProps, TMergedProps> =
219
(stateProps: TStateProps, dispatchProps: TDispatchProps, ownProps: TOwnProps) => TMergedProps;
220
```
221
222
### Utility Types
223
224
Common utility types used throughout React Redux type system.
225
226
```typescript { .api }
227
/**
228
* Equality comparison function type
229
*/
230
type EqualityFn<T> = (a: T, b: T) => boolean;
231
232
/**
233
* Extended equality function with additional parameters
234
*/
235
type ExtendedEqualityFn<T, P> = (a: T, b: T, c: P, d: P) => boolean;
236
237
/**
238
* Utility type for empty objects
239
*/
240
type AnyIfEmpty<T extends object> = keyof T extends never ? any : T;
241
242
/**
243
* Distributive omit utility type
244
*/
245
type DistributiveOmit<T, K extends keyof T> = T extends unknown ? Omit<T, K> : never;
246
247
/**
248
* Extract store action type from store instance
249
*/
250
type ExtractStoreActionType<StoreType extends Store> =
251
StoreType extends Store<any, infer ActionType> ? ActionType : never;
252
253
/**
254
* Props matching utility type for component enhancement
255
*/
256
type Matching<InjectedProps, DecorationTargetProps> = {
257
[P in keyof DecorationTargetProps]: P extends keyof InjectedProps
258
? InjectedProps[P] extends DecorationTargetProps[P]
259
? DecorationTargetProps[P]
260
: InjectedProps[P]
261
: DecorationTargetProps[P];
262
};
263
264
/**
265
* Shared props utility type
266
*/
267
type Shared<InjectedProps, DecorationTargetProps> = {
268
[P in Extract<keyof InjectedProps, keyof DecorationTargetProps>]?: InjectedProps[P] extends DecorationTargetProps[P]
269
? DecorationTargetProps[P]
270
: never;
271
};
272
273
/**
274
* Get component props utility type
275
*/
276
type GetProps<C> = C extends ComponentType<infer P>
277
? C extends ComponentClass<P>
278
? ClassAttributes<InstanceType<C>> & P
279
: P
280
: never;
281
282
/**
283
* Get library managed props utility type
284
*/
285
type GetLibraryManagedProps<C> = JSX.LibraryManagedAttributes<C, GetProps<C>>;
286
287
/**
288
* Mapped utility type
289
*/
290
type Mapped<T> = Identity<{ [k in keyof T]: T[k] }>;
291
292
/**
293
* Identity utility type
294
*/
295
type Identity<T> = T;
296
297
/**
298
* Connect props handling utility
299
*/
300
type ConnectPropsMaybeWithoutContext<TActualOwnProps> = TActualOwnProps extends { context: any }
301
? Omit<ConnectProps, 'context'>
302
: ConnectProps;
303
304
/**
305
* Thunk action creator inference utilities
306
*/
307
type InferThunkActionCreatorType<TActionCreator extends (...args: any[]) => any> =
308
TActionCreator extends (...args: infer TParams) => (...args: any[]) => infer TReturn
309
? (...args: TParams) => TReturn
310
: TActionCreator;
311
312
type HandleThunkActionCreator<TActionCreator> = TActionCreator extends (...args: any[]) => any
313
? InferThunkActionCreatorType<TActionCreator>
314
: TActionCreator;
315
316
/**
317
* Non-object map dispatch to props type
318
*/
319
type MapDispatchToPropsNonObject<TDispatchProps, TOwnProps> =
320
MapDispatchToPropsFactory<TDispatchProps, TOwnProps> |
321
MapDispatchToPropsFunction<TDispatchProps, TOwnProps>;
322
```
323
324
## Advanced TypeScript Usage
325
326
### Multiple Store Types
327
328
Handle multiple stores with different type configurations.
329
330
```typescript
331
import { createContext } from "react";
332
import { createSelectorHook, createDispatchHook } from "react-redux";
333
334
// First store types
335
export type MainRootState = ReturnType<typeof mainStore.getState>;
336
export type MainAppDispatch = typeof mainStore.dispatch;
337
338
// Second store types
339
export type SecondaryRootState = ReturnType<typeof secondaryStore.getState>;
340
export type SecondaryAppDispatch = typeof secondaryStore.dispatch;
341
342
// Custom contexts
343
const SecondaryContext = createContext<ReactReduxContextValue<SecondaryRootState> | null>(null);
344
345
// Create typed hooks for secondary store
346
export const useSecondarySelector = createSelectorHook(SecondaryContext).withTypes<SecondaryRootState>();
347
export const useSecondaryDispatch = createDispatchHook(SecondaryContext).withTypes<SecondaryAppDispatch>();
348
```
349
350
### Complex Connect Typing
351
352
Advanced typing for complex connect scenarios.
353
354
```typescript
355
interface StateProps {
356
user: User;
357
todos: Todo[];
358
}
359
360
interface DispatchProps {
361
fetchUser: (id: string) => void;
362
addTodo: (text: string) => void;
363
}
364
365
interface OwnProps {
366
userId: string;
367
}
368
369
type Props = StateProps & DispatchProps & OwnProps;
370
371
const mapStateToProps = (state: RootState, ownProps: OwnProps): StateProps => ({
372
user: state.users[ownProps.userId],
373
todos: state.todos.filter(todo => todo.userId === ownProps.userId)
374
});
375
376
const mapDispatchToProps: MapDispatchToPropsParam<DispatchProps, OwnProps> = {
377
fetchUser: fetchUserAction,
378
addTodo: addTodoAction
379
};
380
381
const connector = connect(mapStateToProps, mapDispatchToProps);
382
type PropsFromRedux = ConnectedProps<typeof connector>;
383
384
const UserTodos: React.FC<PropsFromRedux & OwnProps> = ({ user, todos, fetchUser, addTodo, userId }) => {
385
// Fully typed component implementation
386
};
387
388
export default connector(UserTodos);
389
```
390
391
### Generic Component Typing
392
393
Create reusable typed components with generics.
394
395
```typescript
396
interface GenericListProps<T> {
397
items: T[];
398
onItemClick: (item: T) => void;
399
renderItem: (item: T) => React.ReactNode;
400
}
401
402
function GenericList<T>({ items, onItemClick, renderItem }: GenericListProps<T>) {
403
return (
404
<div>
405
{items.map((item, index) => (
406
<div key={index} onClick={() => onItemClick(item)}>
407
{renderItem(item)}
408
</div>
409
))}
410
</div>
411
);
412
}
413
414
// Usage with Redux
415
function TodoList() {
416
const todos = useAppSelector((state) => state.todos);
417
const dispatch = useAppDispatch();
418
419
return (
420
<GenericList<Todo>
421
items={todos}
422
onItemClick={(todo) => dispatch(selectTodo(todo.id))}
423
renderItem={(todo) => <span>{todo.text}</span>}
424
/>
425
);
426
}
427
```