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

selector-creation.mddocs/

0

# Selector Creation

1

2

Core functionality for creating memoized selectors using the default `createSelector` function and customizable options.

3

4

## Capabilities

5

6

### createSelector

7

8

Creates a memoized selector that computes derived data from state. The selector will only recompute when one of its input selectors returns a different value.

9

10

```typescript { .api }

11

/**

12

* Creates a memoized selector from input selectors and a result function

13

* @param selectors - Array of input selector functions

14

* @param combiner - Function that combines the results of input selectors

15

* @returns Memoized output selector with additional metadata

16

*/

17

function createSelector<State, Result>(

18

selectors: SelectorArray<State>,

19

combiner: (...args: any[]) => Result

20

): OutputSelector<State, Result>;

21

22

/**

23

* Creates a memoized selector with custom options

24

* @param selectors - Array of input selector functions

25

* @param combiner - Function that combines the results of input selectors

26

* @param options - Configuration options for memoization and dev mode checks

27

* @returns Memoized output selector with additional metadata

28

*/

29

function createSelector<State, Result>(

30

selectors: SelectorArray<State>,

31

combiner: (...args: any[]) => Result,

32

options: CreateSelectorOptions

33

): OutputSelector<State, Result>;

34

35

/**

36

* Variadic overload for inline input selectors

37

* @param selector1 - First input selector

38

* @param selector2 - Second input selector

39

* @param combiner - Function that combines selector results

40

* @returns Memoized output selector

41

*/

42

function createSelector<State, Res1, Res2, Result>(

43

selector1: Selector<State, Res1>,

44

selector2: Selector<State, Res2>,

45

combiner: (res1: Res1, res2: Res2) => Result

46

): OutputSelector<State, Result>;

47

48

// Additional overloads for 3-12 input selectors...

49

```

50

51

**Basic Usage:**

52

53

```typescript

54

import { createSelector } from "reselect";

55

56

// Simple selector with two inputs

57

const selectShopItems = (state) => state.shop.items;

58

const selectTaxPercent = (state) => state.shop.taxPercent;

59

60

const selectSubtotal = createSelector(

61

[selectShopItems],

62

(items) => items.reduce((acc, item) => acc + item.price, 0)

63

);

64

65

const selectTax = createSelector(

66

[selectSubtotal, selectTaxPercent],

67

(subtotal, taxPercent) => subtotal * (taxPercent / 100)

68

);

69

70

const selectTotal = createSelector(

71

[selectSubtotal, selectTax],

72

(subtotal, tax) => ({ total: subtotal + tax })

73

);

74

```

75

76

**With Custom Options:**

77

78

```typescript

79

import { createSelector, lruMemoize } from "reselect";

80

81

const selectExpensiveComputation = createSelector(

82

[selectLargeDataset],

83

(data) => computeExpensiveDerivation(data),

84

{

85

memoize: lruMemoize,

86

memoizeOptions: { maxSize: 10 },

87

devModeChecks: { inputStabilityCheck: 'always' }

88

}

89

);

90

```

91

92

### OutputSelector Interface

93

94

The enhanced selector returned by `createSelector` with additional metadata and methods.

95

96

```typescript { .api }

97

interface OutputSelector<State, Result, Params extends readonly any[] = any[]>

98

extends Selector<State, Result, Params> {

99

/** The original result function passed to createSelector */

100

resultFunc: (...args: any[]) => Result;

101

102

/** The memoization function used by this selector */

103

memoize: UnknownMemoizer;

104

105

/** The arguments memoization function used by this selector */

106

argsMemoize: UnknownMemoizer;

107

108

/** Array of input selectors used by this selector */

109

dependencies: SelectorArray<State>;

110

111

/** Returns the number of times the result function has been recomputed */

112

recomputations: () => number;

113

114

/** Resets the recomputation counter to 0 */

115

resetRecomputations: () => void;

116

117

/** Returns the number of times the dependencies have been recomputed */

118

dependencyRecomputations: () => number;

119

120

/** Resets the dependency recomputation counter to 0 */

121

resetDependencyRecomputations: () => void;

122

123

/** Returns the last computed result */

124

lastResult: () => Result;

125

126

/** The memoized version of the result function */

127

memoizedResultFunc: (...args: any[]) => Result;

128

}

129

```

130

131

**Usage Examples:**

132

133

```typescript

134

const mySelector = createSelector([selectA, selectB], (a, b) => a + b);

135

136

// Check recomputation counts

137

console.log(mySelector.recomputations()); // 0

138

console.log(mySelector.dependencyRecomputations()); // 0

139

140

// Use the selector

141

const result1 = mySelector(state);

142

console.log(mySelector.recomputations()); // 1

143

console.log(mySelector.dependencyRecomputations()); // 1

144

145

// Same inputs won't recompute

146

const result2 = mySelector(state);

147

console.log(mySelector.recomputations()); // Still 1

148

console.log(mySelector.dependencyRecomputations()); // Still 1

149

150

// Get the last result

151

console.log(mySelector.lastResult()); // The computed result

152

153

// Reset counters

154

mySelector.resetRecomputations();

155

mySelector.resetDependencyRecomputations();

156

console.log(mySelector.recomputations()); // 0

157

console.log(mySelector.dependencyRecomputations()); // 0

158

159

// Access the underlying result function

160

const directResult = mySelector.resultFunc(valueA, valueB);

161

```

162

163

### CreateSelectorOptions

164

165

Configuration options for customizing selector behavior.

166

167

```typescript { .api }

168

interface CreateSelectorOptions<MemoizeFunction = typeof weakMapMemoize> {

169

/** Custom memoization function (defaults to weakMapMemoize) */

170

memoize?: MemoizeFunction;

171

172

/** Options passed to the memoization function */

173

memoizeOptions?: ExtractMemoizerFields<MemoizeFunction>;

174

175

/** Custom arguments memoization function (defaults to weakMapMemoize) */

176

argsMemoize?: UnknownMemoizer;

177

178

/** Options passed to the arguments memoization function */

179

argsMemoizeOptions?: unknown[];

180

181

/** Development mode check configuration */

182

devModeChecks?: Partial<DevModeChecks>;

183

}

184

185

interface DevModeChecks {

186

/** Check for unstable input selector results */

187

inputStabilityCheck: DevModeCheckFrequency;

188

189

/** Check if result function is an identity function */

190

identityFunctionCheck: DevModeCheckFrequency;

191

}

192

193

type DevModeCheckFrequency = 'once' | 'always' | 'never';

194

```

195

196

### Parametric Selectors

197

198

Selectors that accept additional parameters beyond state.

199

200

```typescript

201

import { createSelector } from "reselect";

202

203

// Selector with parameters

204

const selectTodoById = createSelector(

205

[(state, id) => state.todos, (state, id) => id],

206

(todos, id) => todos.find(todo => todo.id === id)

207

);

208

209

// Usage with parameters

210

const todo = selectTodoById(state, 42);

211

212

// Factory pattern for parametric selectors

213

const makeSelectorTodosByStatus = () => createSelector(

214

[(state, status) => state.todos, (state, status) => status],

215

(todos, status) => todos.filter(todo => todo.status === status)

216

);

217

218

const selectCompletedTodos = makeSelectorTodosByStatus();

219

const completedTodos = selectCompletedTodos(state, 'completed');

220

```

221

222

### Pre-Typed Selectors

223

224

Create pre-typed versions of `createSelector` with predefined state types to eliminate repetitive type annotations.

225

226

```typescript

227

import { createSelector } from "reselect";

228

229

interface RootState {

230

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

231

alerts: { id: number; read: boolean }[];

232

}

233

234

// Create a pre-typed createSelector with RootState

235

export const createAppSelector = createSelector.withTypes<RootState>();

236

237

// Now you can use createAppSelector without specifying state types

238

const selectTodoIds = createAppSelector(

239

[

240

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

241

state => state.todos

242

],

243

todos => todos.map(({ id }) => id)

244

);

245

246

const selectActiveAlerts = createAppSelector(

247

[state => state.alerts],

248

alerts => alerts.filter(alert => !alert.read)

249

);

250

```

251

252

## Types

253

254

```typescript { .api }

255

type Selector<State = any, Result = unknown, Params extends readonly any[] = any[]> =

256

(state: State, ...params: Params) => Result;

257

258

type SelectorArray<State = any> = readonly Selector<State>[];

259

260

type SelectorResultArray<Selectors extends SelectorArray> = {

261

[Index in keyof Selectors]: Selectors[Index] extends Selector<any, infer Result>

262

? Result

263

: never;

264

};

265

266

type Combiner<Result> = (...args: any[]) => Result;

267

268

type UnknownMemoizer = (func: AnyFunction, ...options: unknown[]) => AnyFunction;

269

270

type AnyFunction = (...args: any[]) => any;

271

```