diff --git a/modules/store/spec/integration.spec.ts b/modules/store/spec/integration.spec.ts index f9998590e0..d6fd04a6d6 100644 --- a/modules/store/spec/integration.spec.ts +++ b/modules/store/spec/integration.spec.ts @@ -243,6 +243,42 @@ describe('ngRx Integration spec', () => { payload: { id: 2 }, }); }); + + it('should use the props in the projector to get a todo', () => { + const getTodosState = createFeatureSelector( + 'todos' + ); + + const getTodosById = createSelector( + getTodosState, + (todos: Todo[], { id }: { id: number }) => + todos.find(todo => todo.id === id) + ); + + let testCase = 1; + const todo$ = store.pipe(select(getTodosById, { id: 2 })); + todo$.subscribe(todo => { + if (testCase === 1) { + expect(todo).toEqual(undefined); + } else if (testCase === 2) { + expect(todo).toEqual({ + id: 2, + text: 'second todo', + completed: false, + }); + } else if (testCase === 3) { + expect(todo).toEqual({ id: 2, text: 'second todo', completed: true }); + } + testCase++; + }); + + store.dispatch({ type: ADD_TODO, payload: { text: 'first todo' } }); + store.dispatch({ type: ADD_TODO, payload: { text: 'second todo' } }); + store.dispatch({ + type: COMPLETE_TODO, + payload: { id: 2 }, + }); + }); }); describe('feature state', () => { diff --git a/modules/store/spec/selector.spec.ts b/modules/store/spec/selector.spec.ts index b6f62e8ea2..75dd01acb0 100644 --- a/modules/store/spec/selector.spec.ts +++ b/modules/store/spec/selector.spec.ts @@ -137,7 +137,9 @@ describe('Selectors', () => { ); selector({}, { value: 47 }); - expect(projectFn).toHaveBeenCalledWith(countOne, countTwo, 47); + expect(projectFn).toHaveBeenCalledWith(countOne, countTwo, 47, { + value: 47, + }); }); it('should be possible to test a projector fn independent from the selectors it is composed of', () => { @@ -363,7 +365,9 @@ describe('Selectors', () => { projectFn )({}, { value: 47 }); - expect(projectFn).toHaveBeenCalledWith(countOne, countTwo, 47); + expect(projectFn).toHaveBeenCalledWith(countOne, countTwo, 47, { + value: 47, + }); }); it('should be possible to test a projector fn independent from the selectors it is composed of', () => { diff --git a/modules/store/src/selector.ts b/modules/store/src/selector.ts index 1f42136531..95c57200db 100644 --- a/modules/store/src/selector.ts +++ b/modules/store/src/selector.ts @@ -90,7 +90,7 @@ export function createSelector( ): MemoizedSelector; export function createSelector( s1: SelectorWithProps, - projector: (s1: S1) => Result + projector: (s1: S1, props: Props) => Result ): MemoizedSelectorWithProps; export function createSelector( selectors: [Selector], @@ -98,7 +98,7 @@ export function createSelector( ): MemoizedSelector; export function createSelector( selectors: [SelectorWithProps], - projector: (s1: S1) => Result + projector: (s1: S1, props: Props) => Result ): MemoizedSelectorWithProps; export function createSelector( @@ -109,7 +109,7 @@ export function createSelector( export function createSelector( s1: SelectorWithProps, s2: SelectorWithProps, - projector: (s1: S1, s2: S2) => Result + projector: (s1: S1, s2: S2, props: Props) => Result ): MemoizedSelectorWithProps; export function createSelector( selectors: [Selector, Selector], @@ -120,7 +120,7 @@ export function createSelector( SelectorWithProps, SelectorWithProps ], - projector: (s1: S1, s2: S2) => Result + projector: (s1: S1, s2: S2, props: Props) => Result ): MemoizedSelectorWithProps; export function createSelector( @@ -133,7 +133,7 @@ export function createSelector( s1: SelectorWithProps, s2: SelectorWithProps, s3: SelectorWithProps, - projector: (s1: S1, s2: S2, s3: S3) => Result + projector: (s1: S1, s2: S2, s3: S3, props: Props) => Result ): MemoizedSelectorWithProps; export function createSelector( selectors: [Selector, Selector, Selector], @@ -145,7 +145,7 @@ export function createSelector( SelectorWithProps, SelectorWithProps ], - projector: (s1: S1, s2: S2, s3: S3) => Result + projector: (s1: S1, s2: S2, s3: S3, props: Props) => Result ): MemoizedSelectorWithProps; export function createSelector( @@ -160,7 +160,7 @@ export function createSelector( s2: SelectorWithProps, s3: SelectorWithProps, s4: SelectorWithProps, - projector: (s1: S1, s2: S2, s3: S3, s4: S4) => Result + projector: (s1: S1, s2: S2, s3: S3, s4: S4, props: Props) => Result ): MemoizedSelectorWithProps; export function createSelector( selectors: [ @@ -178,7 +178,7 @@ export function createSelector( SelectorWithProps, SelectorWithProps ], - projector: (s1: S1, s2: S2, s3: S3, s4: S4) => Result + projector: (s1: S1, s2: S2, s3: S3, s4: S4, props: Props) => Result ): MemoizedSelectorWithProps; export function createSelector( @@ -195,7 +195,7 @@ export function createSelector( s3: SelectorWithProps, s4: SelectorWithProps, s5: SelectorWithProps, - projector: (s1: S1, s2: S2, s3: S3, s4: S4, s5: S5) => Result + projector: (s1: S1, s2: S2, s3: S3, s4: S4, s5: S5, props: Props) => Result ): MemoizedSelectorWithProps; export function createSelector( selectors: [ @@ -215,7 +215,7 @@ export function createSelector( SelectorWithProps, SelectorWithProps ], - projector: (s1: S1, s2: S2, s3: S3, s4: S4, s5: S5) => Result + projector: (s1: S1, s2: S2, s3: S3, s4: S4, s5: S5, props: Props) => Result ): MemoizedSelectorWithProps; export function createSelector( @@ -234,7 +234,15 @@ export function createSelector( s4: SelectorWithProps, s5: SelectorWithProps, s6: SelectorWithProps, - projector: (s1: S1, s2: S2, s3: S3, s4: S4, s5: S5, s6: S6) => Result + projector: ( + s1: S1, + s2: S2, + s3: S3, + s4: S4, + s5: S5, + s6: S6, + props: Props + ) => Result ): MemoizedSelectorWithProps; export function createSelector( selectors: [ @@ -256,7 +264,15 @@ export function createSelector( SelectorWithProps, SelectorWithProps ], - projector: (s1: S1, s2: S2, s3: S3, s4: S4, s5: S5, s6: S6) => Result + projector: ( + s1: S1, + s2: S2, + s3: S3, + s4: S4, + s5: S5, + s6: S6, + props: Props + ) => Result ): MemoizedSelectorWithProps; export function createSelector( @@ -288,7 +304,16 @@ export function createSelector< s5: SelectorWithProps, s6: SelectorWithProps, s7: SelectorWithProps, - projector: (s1: S1, s2: S2, s3: S3, s4: S4, s5: S5, s6: S6, s7: S7) => Result + projector: ( + s1: S1, + s2: S2, + s3: S3, + s4: S4, + s5: S5, + s6: S6, + s7: S7, + props: Props + ) => Result ): MemoizedSelectorWithProps; export function createSelector( selectors: [ @@ -323,7 +348,16 @@ export function createSelector< SelectorWithProps, SelectorWithProps ], - projector: (s1: S1, s2: S2, s3: S3, s4: S4, s5: S5, s6: S6, s7: S7) => Result + projector: ( + s1: S1, + s2: S2, + s3: S3, + s4: S4, + s5: S5, + s6: S6, + s7: S7, + props: Props + ) => Result ): MemoizedSelectorWithProps; export function createSelector( @@ -375,7 +409,8 @@ export function createSelector< s5: S5, s6: S6, s7: S7, - s8: S8 + s8: S8, + props: Props ) => Result ): MemoizedSelectorWithProps; export function createSelector( @@ -431,7 +466,8 @@ export function createSelector< s5: S5, s6: S6, s7: S7, - s8: S8 + s8: S8, + props: Props ) => Result ): MemoizedSelectorWithProps; @@ -447,12 +483,19 @@ export function createSelector( export function defaultStateFn( state: any, - selectors: any[], + selectors: Selector[] | SelectorWithProps[], props: any, memoizedProjector: MemoizedProjection ): any { - const args = selectors.map(fn => fn(state, props)); - return memoizedProjector.memoized.apply(null, args); + if (props === undefined) { + const args = ([]>selectors).map(fn => fn(state)); + return memoizedProjector.memoized.apply(null, args); + } + + const args = ([]>selectors).map(fn => + fn(state, props) + ); + return memoizedProjector.memoized.apply(null, [...args, props]); } export type SelectorFactoryConfig = {