or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

connect.mdhooks.mdindex.mdtypescript.md

typescript.mddocs/

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

```