Skip to content

Commit 351459f

Browse files
feat(store): strict projector for selectors with props (#3640)
BREAKING CHANGE: The projector method has become strict BEFORE: You could pass any arguments to the projector method const selector = createSelector( selectString, // returning a string selectNumber, // returning a number (s, n, prefix: string) => { return prefix + s.repeat(n); } ) // you could pass any argument selector.projector(1, 'a', true); AFTER: const selector = createSelector( selectString, // returning a string selectNumber, // returning a number (s, n, prefix: string) => { return prefix + s.repeat(n); } ) // this throws selector.projector(1, 'a', true); // this does not throw because the arguments have the correct type selector.projector(1, 'a', 'prefix'); Closes #3571
1 parent f825357 commit 351459f

File tree

3 files changed

+179
-20
lines changed

3 files changed

+179
-20
lines changed

modules/store/spec/selector.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -198,11 +198,11 @@ describe('Selectors', () => {
198198
},
199199
projectFn
200200
);
201-
selector.projector('', '', 47);
201+
selector.projector('', '', 47, 'prop');
202202

203203
expect(incrementOne).not.toHaveBeenCalled();
204204
expect(incrementTwo).not.toHaveBeenCalled();
205-
expect(projectFn).toHaveBeenCalledWith('', '', 47);
205+
expect(projectFn).toHaveBeenCalledWith('', '', 47, 'prop');
206206
});
207207

208208
it('should call the projector function when the state changes', () => {
@@ -387,11 +387,11 @@ describe('Selectors', () => {
387387
projectFn
388388
);
389389

390-
selector.projector('', '', 47);
390+
selector.projector('', '', 47, 'prop');
391391

392392
expect(incrementOne).not.toHaveBeenCalled();
393393
expect(incrementTwo).not.toHaveBeenCalled();
394-
expect(projectFn).toHaveBeenCalledWith('', '', 47);
394+
expect(projectFn).toHaveBeenCalledWith('', '', 47, 'prop');
395395
});
396396

397397
it('should call the projector function when the state changes', () => {

modules/store/spec/types/selector.spec.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,43 @@ describe('createSelector()', () => {
3939
});
4040
});
4141
});
42+
43+
describe('createSelector() with props', () => {
44+
const expectSnippet = expecter(
45+
(code) => `
46+
import {createSelector} from '@ngrx/store';
47+
import { MemoizedSelectorWithProps, DefaultProjectorFn } from '@ngrx/store';
48+
49+
${code}
50+
`,
51+
compilerOptions()
52+
);
53+
54+
describe('projector', () => {
55+
it('should require correct arguments by default', () => {
56+
expectSnippet(`
57+
const selectTest = createSelector(
58+
() => 'one',
59+
() => 2,
60+
(one, two, props) => 3
61+
);
62+
selectTest.projector();
63+
`).toFail(/Expected 3 arguments, but got 0./);
64+
});
65+
it('should not require parameters for existing explicitly loosely typed selectors', () => {
66+
expectSnippet(`
67+
const selectTest: MemoizedSelectorWithProps<
68+
unknown,
69+
number,
70+
any,
71+
DefaultProjectorFn<number>
72+
> = createSelector(
73+
() => 'one',
74+
() => 2,
75+
(one, two, props) => 3
76+
);
77+
selectTest.projector();
78+
`).toSucceed();
79+
});
80+
});
81+
});

modules/store/src/selector.ts

Lines changed: 135 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ export function defaultMemoize(
9191
}
9292

9393
/* eslint-disable prefer-rest-params, prefer-spread */
94+
9495
// disabled because of the use of `arguments`
9596
function memoized(): any {
9697
if (overrideResult !== undefined) {
@@ -222,7 +223,12 @@ export function createSelector<State, Slices extends unknown[], Result>(
222223
export function createSelector<State, Props, S1, Result>(
223224
s1: SelectorWithProps<State, Props, S1>,
224225
projector: (s1: S1, props: Props) => Result
225-
): MemoizedSelectorWithProps<State, Props, Result>;
226+
): MemoizedSelectorWithProps<
227+
State,
228+
Props,
229+
Result,
230+
(s1: S1, props: Props) => Result
231+
>;
226232

227233
/**
228234
* @deprecated Selectors with props are deprecated, for more info see {@link https://github.com/ngrx/platform/issues/2980 Github Issue}
@@ -231,7 +237,12 @@ export function createSelector<State, Props, S1, S2, Result>(
231237
s1: SelectorWithProps<State, Props, S1>,
232238
s2: SelectorWithProps<State, Props, S2>,
233239
projector: (s1: S1, s2: S2, props: Props) => Result
234-
): MemoizedSelectorWithProps<State, Props, Result>;
240+
): MemoizedSelectorWithProps<
241+
State,
242+
Props,
243+
Result,
244+
(s1: S1, s2: S2, props: Props) => Result
245+
>;
235246

236247
/**
237248
* @deprecated Selectors with props are deprecated, for more info see {@link https://github.com/ngrx/platform/issues/2980 Github Issue}
@@ -241,7 +252,12 @@ export function createSelector<State, Props, S1, S2, S3, Result>(
241252
s2: SelectorWithProps<State, Props, S2>,
242253
s3: SelectorWithProps<State, Props, S3>,
243254
projector: (s1: S1, s2: S2, s3: S3, props: Props) => Result
244-
): MemoizedSelectorWithProps<State, Props, Result>;
255+
): MemoizedSelectorWithProps<
256+
State,
257+
Props,
258+
Result,
259+
(s1: S1, s2: S2, s3: S3, props: Props) => Result
260+
>;
245261

246262
/**
247263
* @deprecated Selectors with props are deprecated, for more info see {@link https://github.com/ngrx/platform/issues/2980 Github Issue}
@@ -252,7 +268,12 @@ export function createSelector<State, Props, S1, S2, S3, S4, Result>(
252268
s3: SelectorWithProps<State, Props, S3>,
253269
s4: SelectorWithProps<State, Props, S4>,
254270
projector: (s1: S1, s2: S2, s3: S3, s4: S4, props: Props) => Result
255-
): MemoizedSelectorWithProps<State, Props, Result>;
271+
): MemoizedSelectorWithProps<
272+
State,
273+
Props,
274+
Result,
275+
(s1: S1, s2: S2, s3: S3, s4: S4, props: Props) => Result
276+
>;
256277

257278
/**
258279
* @deprecated Selectors with props are deprecated, for more info see {@link https://github.com/ngrx/platform/issues/2980 Github Issue}
@@ -264,7 +285,12 @@ export function createSelector<State, Props, S1, S2, S3, S4, S5, Result>(
264285
s4: SelectorWithProps<State, Props, S4>,
265286
s5: SelectorWithProps<State, Props, S5>,
266287
projector: (s1: S1, s2: S2, s3: S3, s4: S4, s5: S5, props: Props) => Result
267-
): MemoizedSelectorWithProps<State, Props, Result>;
288+
): MemoizedSelectorWithProps<
289+
State,
290+
Props,
291+
Result,
292+
(s1: S1, s2: S2, s3: S3, s4: S4, s5: S5, props: Props) => Result
293+
>;
268294

269295
/**
270296
* @deprecated Selectors with props are deprecated, for more info see {@link https://github.com/ngrx/platform/issues/2980 Github Issue}
@@ -285,7 +311,12 @@ export function createSelector<State, Props, S1, S2, S3, S4, S5, S6, Result>(
285311
s6: S6,
286312
props: Props
287313
) => Result
288-
): MemoizedSelectorWithProps<State, Props, Result>;
314+
): MemoizedSelectorWithProps<
315+
State,
316+
Props,
317+
Result,
318+
(s1: S1, s2: S2, s3: S3, s4: S4, s5: S5, s6: S6, props: Props) => Result
319+
>;
289320

290321
/**
291322
* @deprecated Selectors with props are deprecated, for more info see {@link https://github.com/ngrx/platform/issues/2980 Github Issue}
@@ -319,7 +350,21 @@ export function createSelector<
319350
s7: S7,
320351
props: Props
321352
) => Result
322-
): MemoizedSelectorWithProps<State, Props, Result>;
353+
): MemoizedSelectorWithProps<
354+
State,
355+
Props,
356+
Result,
357+
(
358+
s1: S1,
359+
s2: S2,
360+
s3: S3,
361+
s4: S4,
362+
s5: S5,
363+
s6: S6,
364+
s7: S7,
365+
props: Props
366+
) => Result
367+
>;
323368

324369
/**
325370
* @deprecated Selectors with props are deprecated, for more info see {@link https://github.com/ngrx/platform/issues/2980 Github Issue}
@@ -356,7 +401,22 @@ export function createSelector<
356401
s8: S8,
357402
props: Props
358403
) => Result
359-
): MemoizedSelectorWithProps<State, Props, Result>;
404+
): MemoizedSelectorWithProps<
405+
State,
406+
Props,
407+
Result,
408+
(
409+
s1: S1,
410+
s2: S2,
411+
s3: S3,
412+
s4: S4,
413+
s5: S5,
414+
s6: S6,
415+
s7: S7,
416+
s8: S8,
417+
props: Props
418+
) => Result
419+
>;
360420

361421
export function createSelector<State, Slices extends unknown[], Result>(
362422
selectors: Selector<State, unknown>[] &
@@ -370,7 +430,12 @@ export function createSelector<State, Slices extends unknown[], Result>(
370430
export function createSelector<State, Props, S1, Result>(
371431
selectors: [SelectorWithProps<State, Props, S1>],
372432
projector: (s1: S1, props: Props) => Result
373-
): MemoizedSelectorWithProps<State, Props, Result>;
433+
): MemoizedSelectorWithProps<
434+
State,
435+
Props,
436+
Result,
437+
(s1: S1, props: Props) => Result
438+
>;
374439

375440
/**
376441
* @deprecated Selectors with props are deprecated, for more info see {@link https://github.com/ngrx/platform/issues/2980 Github Issue}
@@ -381,7 +446,12 @@ export function createSelector<State, Props, S1, S2, Result>(
381446
SelectorWithProps<State, Props, S2>
382447
],
383448
projector: (s1: S1, s2: S2, props: Props) => Result
384-
): MemoizedSelectorWithProps<State, Props, Result>;
449+
): MemoizedSelectorWithProps<
450+
State,
451+
Props,
452+
Result,
453+
(s1: S1, s2: S2, props: Props) => Result
454+
>;
385455

386456
/**
387457
* @deprecated Selectors with props are deprecated, for more info see {@link https://github.com/ngrx/platform/issues/2980 Github Issue}
@@ -393,7 +463,12 @@ export function createSelector<State, Props, S1, S2, S3, Result>(
393463
SelectorWithProps<State, Props, S3>
394464
],
395465
projector: (s1: S1, s2: S2, s3: S3, props: Props) => Result
396-
): MemoizedSelectorWithProps<State, Props, Result>;
466+
): MemoizedSelectorWithProps<
467+
State,
468+
Props,
469+
Result,
470+
(s1: S1, s2: S2, s3: S3, props: Props) => Result
471+
>;
397472

398473
/**
399474
* @deprecated Selectors with props are deprecated, for more info see {@link https://github.com/ngrx/platform/issues/2980 Github Issue}
@@ -406,7 +481,12 @@ export function createSelector<State, Props, S1, S2, S3, S4, Result>(
406481
SelectorWithProps<State, Props, S4>
407482
],
408483
projector: (s1: S1, s2: S2, s3: S3, s4: S4, props: Props) => Result
409-
): MemoizedSelectorWithProps<State, Props, Result>;
484+
): MemoizedSelectorWithProps<
485+
State,
486+
Props,
487+
Result,
488+
(s1: S1, s2: S2, s3: S3, s4: S4, props: Props) => Result
489+
>;
410490

411491
/**
412492
* @deprecated Selectors with props are deprecated, for more info see {@link https://github.com/ngrx/platform/issues/2980 Github Issue}
@@ -420,7 +500,12 @@ export function createSelector<State, Props, S1, S2, S3, S4, S5, Result>(
420500
SelectorWithProps<State, Props, S5>
421501
],
422502
projector: (s1: S1, s2: S2, s3: S3, s4: S4, s5: S5, props: Props) => Result
423-
): MemoizedSelectorWithProps<State, Props, Result>;
503+
): MemoizedSelectorWithProps<
504+
State,
505+
Props,
506+
Result,
507+
(s1: S1, s2: S2, s3: S3, s4: S4, s5: S5, props: Props) => Result
508+
>;
424509

425510
/**
426511
* @deprecated Selectors with props are deprecated, for more info see {@link https://github.com/ngrx/platform/issues/2980 Github Issue}
@@ -443,7 +528,12 @@ export function createSelector<State, Props, S1, S2, S3, S4, S5, S6, Result>(
443528
s6: S6,
444529
props: Props
445530
) => Result
446-
): MemoizedSelectorWithProps<State, Props, Result>;
531+
): MemoizedSelectorWithProps<
532+
State,
533+
Props,
534+
Result,
535+
(s1: S1, s2: S2, s3: S3, s4: S4, s5: S5, s6: S6, props: Props) => Result
536+
>;
447537

448538
/**
449539
* @deprecated Selectors with props are deprecated, for more info see {@link https://github.com/ngrx/platform/issues/2980 Github Issue}
@@ -479,7 +569,21 @@ export function createSelector<
479569
s7: S7,
480570
props: Props
481571
) => Result
482-
): MemoizedSelectorWithProps<State, Props, Result>;
572+
): MemoizedSelectorWithProps<
573+
State,
574+
Props,
575+
Result,
576+
(
577+
s1: S1,
578+
s2: S2,
579+
s3: S3,
580+
s4: S4,
581+
s5: S5,
582+
s6: S6,
583+
s7: S7,
584+
props: Props
585+
) => Result
586+
>;
483587

484588
/**
485589
* @deprecated Selectors with props are deprecated, for more info see {@link https://github.com/ngrx/platform/issues/2980 Github Issue}
@@ -518,7 +622,22 @@ export function createSelector<
518622
s8: S8,
519623
props: Props
520624
) => Result
521-
): MemoizedSelectorWithProps<State, Props, Result>;
625+
): MemoizedSelectorWithProps<
626+
State,
627+
Props,
628+
Result,
629+
(
630+
s1: S1,
631+
s2: S2,
632+
s3: S3,
633+
s4: S4,
634+
s5: S5,
635+
s6: S6,
636+
s7: S7,
637+
s8: S8,
638+
props: Props
639+
) => Result
640+
>;
522641

523642
export function createSelector(
524643
...input: any[]

0 commit comments

Comments
 (0)