@@ -56,6 +56,14 @@ export type Projector<Selectors extends Observable<unknown>[], Result> = (
5656 ...args : SelectorResults < Selectors >
5757) => Result ;
5858
59+ type SignalsProjector < Signals extends Signal < unknown > [ ] , Result > = (
60+ ...values : {
61+ [ Key in keyof Signals ] : Signals [ Key ] extends Signal < infer Value >
62+ ? Value
63+ : never ;
64+ }
65+ ) => Result ;
66+
5967@Injectable ( )
6068export class ComponentStore < T extends object > implements OnDestroy {
6169 // Should be used only in ngOnDestroy.
@@ -67,10 +75,12 @@ export class ComponentStore<T extends object> implements OnDestroy {
6775 private isInitialized = false ;
6876 // Needs to be after destroy$ is declared because it's used in select.
6977 readonly state$ : Observable < T > = this . select ( ( s ) => s ) ;
70- private ɵhasProvider = false ;
71-
7278 // Signal of state$
73- readonly state : Signal < T > ;
79+ readonly state : Signal < T > = toSignal (
80+ this . state$ . pipe ( takeUntil ( this . destroy$ ) ) ,
81+ { requireSync : false , manualCleanup : true }
82+ ) ;
83+ private ɵhasProvider = false ;
7484
7585 constructor ( @Optional ( ) @Inject ( INITIAL_STATE_TOKEN ) defaultState ?: T ) {
7686 // State can be initialized either through constructor or setState.
@@ -79,10 +89,6 @@ export class ComponentStore<T extends object> implements OnDestroy {
7989 }
8090
8191 this . checkProviderForHooks ( ) ;
82- this . state = toSignal ( this . stateSubject$ . pipe ( takeUntil ( this . destroy$ ) ) , {
83- requireSync : false ,
84- manualCleanup : true ,
85- } ) ;
8692 }
8793
8894 /** Completes all relevant Observable streams. */
@@ -293,12 +299,40 @@ export class ComponentStore<T extends object> implements OnDestroy {
293299 }
294300
295301 /**
296- * Returns a signal of the provided projector function.
297- *
298- * @param projector projector function
302+ * Creates a signal from the provided state projector function.
303+ */
304+ selectSignal < Result > ( projector : ( state : T ) => Result ) : Signal < Result > ;
305+ /**
306+ * Creates a signal by combining provided signals.
299307 */
300- selectSignal < K > ( projector : ( state : T ) => K ) : Signal < K > {
301- return computed ( ( ) => projector ( this . state ( ) ) ) ;
308+ selectSignal < Signals extends Signal < unknown > [ ] , Result > (
309+ ...signalsWithProjector : [
310+ ...selectors : Signals ,
311+ projector : SignalsProjector < Signals , Result >
312+ ]
313+ ) : Signal < Result > ;
314+ selectSignal (
315+ ...args :
316+ | [ ( state : T ) => unknown ]
317+ | [
318+ ...signals : Signal < unknown > [ ] ,
319+ projector : ( ...values : unknown [ ] ) => unknown
320+ ]
321+ ) : Signal < unknown > {
322+ if ( args . length === 1 ) {
323+ const projector = args [ 0 ] as ( state : T ) => unknown ;
324+ return computed ( ( ) => projector ( this . state ( ) ) ) ;
325+ }
326+
327+ const signals = args . slice ( 0 , - 1 ) as Signal < unknown > [ ] ;
328+ const projector = args [ args . length - 1 ] as (
329+ ...values : unknown [ ]
330+ ) => unknown ;
331+
332+ return computed ( ( ) => {
333+ const values = signals . map ( ( signal ) => signal ( ) ) ;
334+ return projector ( ...values ) ;
335+ } ) ;
302336 }
303337
304338 /**
0 commit comments