@@ -2,13 +2,24 @@ import { Selector } from './models';
2
2
3
3
export type AnyFn = ( ...args : any [ ] ) => any ;
4
4
5
+ export type MemoizedProjection = { memoized : AnyFn ; reset : ( ) => void } ;
6
+
7
+ export type MemoizeFn = ( t : AnyFn ) => MemoizedProjection ;
8
+
5
9
export interface MemoizedSelector < State , Result >
6
10
extends Selector < State , Result > {
7
11
release ( ) : void ;
8
12
projector : AnyFn ;
9
13
}
10
14
11
- export function memoize ( t : AnyFn ) : { memoized : AnyFn ; reset : ( ) => void } {
15
+ export function isEqualCheck ( a : any , b : any ) : boolean {
16
+ return a === b ;
17
+ }
18
+
19
+ export function defaultMemoize (
20
+ t : AnyFn ,
21
+ isEqual = isEqualCheck
22
+ ) : MemoizedProjection {
12
23
let lastArguments : null | IArguments = null ;
13
24
let lastResult : any = null ;
14
25
@@ -24,8 +35,9 @@ export function memoize(t: AnyFn): { memoized: AnyFn; reset: () => void } {
24
35
25
36
return lastResult ;
26
37
}
38
+
27
39
for ( let i = 0 ; i < arguments . length ; i ++ ) {
28
- if ( arguments [ i ] !== lastArguments [ i ] ) {
40
+ if ( ! isEqual ( arguments [ i ] , lastArguments [ i ] ) ) {
29
41
lastResult = t . apply ( null , arguments ) ;
30
42
lastArguments = arguments ;
31
43
@@ -184,41 +196,75 @@ export function createSelector<State, S1, S2, S3, S4, S5, S6, S7, S8, Result>(
184
196
s8 : S8
185
197
) => Result
186
198
) : MemoizedSelector < State , Result > ;
187
- export function createSelector ( ...input : any [ ] ) : Selector < any , any > {
188
- let args = input ;
189
- if ( Array . isArray ( args [ 0 ] ) ) {
190
- const [ head , ...tail ] = args ;
191
- args = [ ...head , ...tail ] ;
192
- }
199
+ export function createSelector ( ...input : any [ ] ) {
200
+ return createSelectorFactory ( defaultMemoize ) ( ...input ) ;
201
+ }
193
202
194
- const selectors = args . slice ( 0 , args . length - 1 ) ;
195
- const projector = args [ args . length - 1 ] ;
196
- const memoizedSelectors = selectors . filter (
197
- ( selector : any ) =>
198
- selector . release && typeof selector . release === 'function'
199
- ) ;
203
+ export function defaultStateFn (
204
+ state : any ,
205
+ selectors : Selector < any , any > [ ] ,
206
+ memoizedProjector : MemoizedProjection
207
+ ) : any {
208
+ const args = selectors . map ( fn => fn ( state ) ) ;
200
209
201
- const memoizedProjector = memoize ( function ( ...selectors : any [ ] ) {
202
- return projector . apply ( null , selectors ) ;
203
- } ) ;
210
+ return memoizedProjector . memoized . apply ( null , args ) ;
211
+ }
204
212
205
- const memoizedState = memoize ( function ( state : any ) {
206
- const args = selectors . map ( fn => fn ( state ) ) ;
213
+ export type SelectorFactoryConfig < T = any , V = any > = {
214
+ stateFn : (
215
+ state : T ,
216
+ selectors : Selector < any , any > [ ] ,
217
+ memoizedProjector : MemoizedProjection
218
+ ) => V ;
219
+ } ;
207
220
208
- return memoizedProjector . memoized . apply ( null , args ) ;
209
- } ) ;
221
+ export function createSelectorFactory < T = any , V = any > (
222
+ memoize : MemoizeFn
223
+ ) : ( ...input : any [ ] ) => Selector < T , V > ;
224
+ export function createSelectorFactory < T = any , V = any > (
225
+ memoize : MemoizeFn ,
226
+ options : SelectorFactoryConfig < T , V >
227
+ ) : ( ...input : any [ ] ) => Selector < T , V > ;
228
+ export function createSelectorFactory (
229
+ memoize : MemoizeFn ,
230
+ options : SelectorFactoryConfig < any , any > = {
231
+ stateFn : defaultStateFn ,
232
+ }
233
+ ) {
234
+ return function ( ...input : any [ ] ) : Selector < any , any > {
235
+ let args = input ;
236
+ if ( Array . isArray ( args [ 0 ] ) ) {
237
+ const [ head , ...tail ] = args ;
238
+ args = [ ...head , ...tail ] ;
239
+ }
210
240
211
- function release ( ) {
212
- memoizedState . reset ( ) ;
213
- memoizedProjector . reset ( ) ;
241
+ const selectors = args . slice ( 0 , args . length - 1 ) ;
242
+ const projector = args [ args . length - 1 ] ;
243
+ const memoizedSelectors = selectors . filter (
244
+ ( selector : any ) =>
245
+ selector . release && typeof selector . release === 'function'
246
+ ) ;
214
247
215
- memoizedSelectors . forEach ( selector => selector . release ( ) ) ;
216
- }
248
+ const memoizedProjector = memoize ( function ( ...selectors : any [ ] ) {
249
+ return projector . apply ( null , selectors ) ;
250
+ } ) ;
251
+
252
+ const memoizedState = defaultMemoize ( function ( state : any ) {
253
+ return options . stateFn . apply ( null , [ state , selectors , memoizedProjector ] ) ;
254
+ } ) ;
255
+
256
+ function release ( ) {
257
+ memoizedState . reset ( ) ;
258
+ memoizedProjector . reset ( ) ;
259
+
260
+ memoizedSelectors . forEach ( selector => selector . release ( ) ) ;
261
+ }
217
262
218
- return Object . assign ( memoizedState . memoized , {
219
- release,
220
- projector : memoizedProjector . memoized ,
221
- } ) ;
263
+ return Object . assign ( memoizedState . memoized , {
264
+ release,
265
+ projector : memoizedProjector . memoized ,
266
+ } ) ;
267
+ } ;
222
268
}
223
269
224
270
export function createFeatureSelector < T > (
0 commit comments