or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

development.mdindex.mdmemoization.mdselector-creation.mdselector-creator.mdstructured-selectors.md

structured-selectors.mddocs/

0

# Structured Selectors

1

2

Utility for creating selectors that return objects with the same keys as the input selectors object, where each value is computed by the corresponding selector.

3

4

## Capabilities

5

6

### createStructuredSelector

7

8

Creates a selector that returns an object with the same shape as the input selectors object, but with values computed by running each selector.

9

10

```typescript { .api }

11

/**

12

* Creates a structured selector from an object of selectors

13

* @param selectors - Object where each property is a selector function

14

* @returns OutputSelector that returns object with same keys but computed values

15

*/

16

function createStructuredSelector<TSelectors extends SelectorsObject>(

17

selectors: TSelectors

18

): OutputSelector<

19

GetStateFromSelectors<TSelectors>,

20

SelectorResultsMap<TSelectors>

21

>;

22

23

/**

24

* Creates a structured selector with a custom selector creator

25

* @param selectors - Object where each property is a selector function

26

* @param selectorCreator - Custom createSelector function to use

27

* @returns OutputSelector using the custom selector creator

28

*/

29

function createStructuredSelector<TSelectors extends SelectorsObject>(

30

selectors: TSelectors,

31

selectorCreator: CreateSelectorFunction

32

): OutputSelector<

33

GetStateFromSelectors<TSelectors>,

34

SelectorResultsMap<TSelectors>

35

>;

36

```

37

38

**Basic Usage:**

39

40

```typescript

41

import { createStructuredSelector } from "reselect";

42

43

// Individual selectors

44

const selectItems = (state) => state.items;

45

const selectLoading = (state) => state.loading;

46

const selectError = (state) => state.error;

47

const selectUser = (state) => state.user;

48

49

// Create structured selector

50

const selectAppData = createStructuredSelector({

51

items: selectItems,

52

loading: selectLoading,

53

error: selectError,

54

user: selectUser

55

});

56

57

// Usage

58

const appData = selectAppData(state);

59

// Result: { items: [...], loading: false, error: null, user: {...} }

60

```

61

62

**With Custom Selector Creator:**

63

64

```typescript

65

import { createStructuredSelector, createSelectorCreator, lruMemoize } from "reselect";

66

67

// Custom selector creator with LRU memoization

68

const createLRUSelector = createSelectorCreator({

69

memoize: lruMemoize,

70

memoizeOptions: { maxSize: 10 }

71

});

72

73

// Structured selector using custom creator

74

const selectDashboardData = createStructuredSelector({

75

stats: selectStats,

76

recentActivity: selectRecentActivity,

77

notifications: selectNotifications

78

}, createLRUSelector);

79

```

80

81

**Nested Structured Selectors:**

82

83

```typescript

84

import { createStructuredSelector } from "reselect";

85

86

// Create nested structure

87

const selectUserProfile = createStructuredSelector({

88

personal: createStructuredSelector({

89

name: (state) => state.user.name,

90

email: (state) => state.user.email,

91

avatar: (state) => state.user.avatar

92

}),

93

preferences: createStructuredSelector({

94

theme: (state) => state.user.preferences.theme,

95

language: (state) => state.user.preferences.language,

96

notifications: (state) => state.user.preferences.notifications

97

}),

98

stats: createStructuredSelector({

99

loginCount: (state) => state.user.stats.loginCount,

100

lastLogin: (state) => state.user.stats.lastLogin

101

})

102

});

103

104

// Result has nested structure:

105

// {

106

// personal: { name: "...", email: "...", avatar: "..." },

107

// preferences: { theme: "...", language: "...", notifications: ... },

108

// stats: { loginCount: 42, lastLogin: "..." }

109

// }

110

```

111

112

### Root State Selectors

113

114

Creating selectors for each key in a root state object.

115

116

```typescript

117

import { createStructuredSelector } from "reselect";

118

119

// For a state shape like: { todos: [...], users: [...], settings: {...} }

120

const selectAllSlices = createStructuredSelector({

121

todos: (state) => state.todos,

122

users: (state) => state.users,

123

settings: (state) => state.settings

124

});

125

126

// Equivalent to manually writing:

127

const selectAllSlicesManual = createSelector(

128

[(state) => state.todos, (state) => state.users, (state) => state.settings],

129

(todos, users, settings) => ({ todos, users, settings })

130

);

131

```

132

133

### TypeScript Usage with Typed State

134

135

```typescript

136

interface RootState {

137

users: User[];

138

posts: Post[];

139

ui: {

140

loading: boolean;

141

error: string | null;

142

};

143

}

144

145

interface User {

146

id: number;

147

name: string;

148

email: string;

149

}

150

151

interface Post {

152

id: number;

153

title: string;

154

authorId: number;

155

}

156

157

// Typed structured selector

158

const selectPageData = createStructuredSelector({

159

users: (state: RootState) => state.users,

160

posts: (state: RootState) => state.posts,

161

loading: (state: RootState) => state.ui.loading,

162

error: (state: RootState) => state.ui.error

163

});

164

165

// TypeScript infers the return type:

166

// {

167

// users: User[];

168

// posts: Post[];

169

// loading: boolean;

170

// error: string | null;

171

// }

172

```

173

174

### Advanced Patterns

175

176

**Computed Properties in Structured Selectors:**

177

178

```typescript

179

import { createStructuredSelector, createSelector } from "reselect";

180

181

// Mix simple selectors with computed ones

182

const selectOrderSummary = createStructuredSelector({

183

// Simple selectors

184

items: (state) => state.cart.items,

185

customer: (state) => state.customer,

186

187

// Computed selectors

188

subtotal: createSelector(

189

[(state) => state.cart.items],

190

(items) => items.reduce((sum, item) => sum + item.price * item.quantity, 0)

191

),

192

193

tax: createSelector(

194

[(state) => state.cart.items, (state) => state.customer.taxRate],

195

(items, taxRate) => {

196

const subtotal = items.reduce((sum, item) => sum + item.price * item.quantity, 0);

197

return subtotal * taxRate;

198

}

199

),

200

201

total: createSelector(

202

[

203

(state) => state.cart.items,

204

(state) => state.customer.taxRate

205

],

206

(items, taxRate) => {

207

const subtotal = items.reduce((sum, item) => sum + item.price * item.quantity, 0);

208

const tax = subtotal * taxRate;

209

return subtotal + tax;

210

}

211

)

212

});

213

```

214

215

### Pre-Typed Structured Selectors

216

217

Create pre-typed versions of `createStructuredSelector` with predefined state types.

218

219

```typescript

220

import { createStructuredSelector } from "reselect";

221

222

interface RootState {

223

todos: { id: number; completed: boolean }[];

224

users: { id: number; name: string }[];

225

ui: { loading: boolean; error: string | null };

226

}

227

228

// Create a pre-typed createStructuredSelector

229

export const createStructuredAppSelector = createStructuredSelector.withTypes<RootState>();

230

231

// Now use it without specifying state types

232

const selectAppData = createStructuredAppSelector({

233

// Type of `state` is automatically set to `RootState`

234

todos: state => state.todos,

235

users: state => state.users,

236

loading: state => state.ui.loading,

237

error: state => state.ui.error

238

});

239

240

// TypeScript knows the return type:

241

// {

242

// todos: { id: number; completed: boolean }[];

243

// users: { id: number; name: string }[];

244

// loading: boolean;

245

// error: string | null;

246

// }

247

```

248

249

## Types

250

251

```typescript { .api }

252

type SelectorsObject = Record<string, Selector>;

253

254

type SelectorResultsMap<TObject extends SelectorsObject> = {

255

[Key in keyof TObject]: ReturnType<TObject[Key]>;

256

};

257

258

type RootStateSelectors<TState> = {

259

[Key in keyof TState]: Selector<TState, TState[Key]>;

260

};

261

262

type GetStateFromSelectors<TSelectors extends SelectorsObject> =

263

TSelectors[keyof TSelectors] extends Selector<infer State, any> ? State : never;

264

265

interface StructuredSelectorCreator {

266

<TSelectors extends SelectorsObject>(

267

selectors: TSelectors

268

): OutputSelector<GetStateFromSelectors<TSelectors>, SelectorResultsMap<TSelectors>>;

269

270

<TSelectors extends SelectorsObject>(

271

selectors: TSelectors,

272

selectorCreator: CreateSelectorFunction

273

): OutputSelector<GetStateFromSelectors<TSelectors>, SelectorResultsMap<TSelectors>>;

274

275

withTypes: <OverrideStateType>() => StructuredSelectorCreator<OverrideStateType>;

276

}

277

278

type TypedStructuredSelectorCreator<State> = <TSelectors extends RootStateSelectors<State>>(

279

selectors: TSelectors

280

) => OutputSelector<State, SelectorResultsMap<TSelectors>>;

281

```