@@ -34,6 +34,7 @@ import {
34
34
isDevMode ,
35
35
Signal ,
36
36
computed ,
37
+ type ValueEqualityFn ,
37
38
} from '@angular/core' ;
38
39
import { isOnStateInitDefined , isOnStoreInitDefined } from './lifecycle_hooks' ;
39
40
import { toSignal } from './to-signal' ;
@@ -64,6 +65,13 @@ type SignalsProjector<Signals extends Signal<unknown>[], Result> = (
64
65
}
65
66
) => Result ;
66
67
68
+ interface SelectSignalOptions < T > {
69
+ /**
70
+ * A comparison function which defines equality for select results.
71
+ */
72
+ equal ?: ValueEqualityFn < T > ;
73
+ }
74
+
67
75
@Injectable ( )
68
76
export class ComponentStore < T extends object > implements OnDestroy {
69
77
// Should be used only in ngOnDestroy.
@@ -301,38 +309,69 @@ export class ComponentStore<T extends object> implements OnDestroy {
301
309
/**
302
310
* Creates a signal from the provided state projector function.
303
311
*/
304
- selectSignal < Result > ( projector : ( state : T ) => Result ) : Signal < Result > ;
312
+ selectSignal < Result > (
313
+ projector : ( state : T ) => Result ,
314
+ options ?: SelectSignalOptions < Result >
315
+ ) : Signal < Result > ;
316
+ /**
317
+ * Creates a signal by combining provided signals.
318
+ */
319
+ selectSignal < Signals extends Signal < unknown > [ ] , Result > (
320
+ ...args : [ ...signals : Signals , projector : SignalsProjector < Signals , Result > ]
321
+ ) : Signal < Result > ;
305
322
/**
306
323
* Creates a signal by combining provided signals.
307
324
*/
308
325
selectSignal < Signals extends Signal < unknown > [ ] , Result > (
309
- ...signalsWithProjector : [
310
- ...selectors : Signals ,
311
- projector : SignalsProjector < Signals , Result >
326
+ ...args : [
327
+ ...signals : Signals ,
328
+ projector : SignalsProjector < Signals , Result > ,
329
+ options : SelectSignalOptions < Result >
312
330
]
313
331
) : Signal < Result > ;
314
332
selectSignal (
315
333
...args :
316
- | [ ( state : T ) => unknown ]
334
+ | [ ( state : T ) => unknown , SelectSignalOptions < unknown > ? ]
317
335
| [
318
336
...signals : Signal < unknown > [ ] ,
319
337
projector : ( ...values : unknown [ ] ) => unknown
320
338
]
339
+ | [
340
+ ...signals : Signal < unknown > [ ] ,
341
+ projector : ( ...values : unknown [ ] ) => unknown ,
342
+ options : SelectSignalOptions < unknown >
343
+ ]
321
344
) : Signal < unknown > {
322
345
if ( args . length === 1 ) {
323
346
const projector = args [ 0 ] as ( state : T ) => unknown ;
324
347
return computed ( ( ) => projector ( this . state ( ) ) ) ;
325
348
}
326
349
327
- const signals = args . slice ( 0 , - 1 ) as Signal < unknown > [ ] ;
328
- const projector = args [ args . length - 1 ] as (
350
+ const optionsOrProjector = args [ args . length - 1 ] as (
329
351
...values : unknown [ ]
330
- ) => unknown ;
352
+ ) => unknown | SelectSignalOptions < unknown > ;
353
+ if ( typeof optionsOrProjector === 'function' ) {
354
+ const signals = args . slice ( 0 , - 1 ) as Signal < unknown > [ ] ;
355
+
356
+ return computed ( ( ) => {
357
+ const values = signals . map ( ( signal ) => signal ( ) ) ;
358
+ return optionsOrProjector ( ...values ) ;
359
+ } ) ;
360
+ }
331
361
362
+ if ( args . length === 2 ) {
363
+ const projector = args [ 0 ] as ( state : T ) => unknown ;
364
+ return computed ( ( ) => projector ( this . state ( ) ) , optionsOrProjector ) ;
365
+ }
366
+
367
+ const signals = args . slice ( 0 , - 2 ) as Signal < unknown > [ ] ;
368
+ const projector = args [ args . length - 2 ] as (
369
+ ...values : unknown [ ]
370
+ ) => unknown ;
332
371
return computed ( ( ) => {
333
372
const values = signals . map ( ( signal ) => signal ( ) ) ;
334
373
return projector ( ...values ) ;
335
- } ) ;
374
+ } , optionsOrProjector ) ;
336
375
}
337
376
338
377
/**
0 commit comments