Skip to content

Commit c2ee493

Browse files
feat(store) introduce opt-in strict projectors from createSelector
1 parent cffb598 commit c2ee493

File tree

2 files changed

+52
-7
lines changed

2 files changed

+52
-7
lines changed

modules/router-store/spec/types/selectors.spec.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,15 +105,22 @@ describe('router selectors', () => {
105105
);
106106
});
107107

108-
it('selectUrl should return string', () => {
108+
it('selectUrl with strict option should return strict selector with [string] slices and string projection', () => {
109109
expectSnippet(`
110110
export const selector = createSelector(
111+
selectUrl,
112+
url => url,
113+
{ strict: true }
114+
);
115+
`).toInfer('selector', 'StrictMemoizedSelector<[string], string, State>');
116+
});
117+
118+
it('selectUrl with strict generic params should return strict selector with [string] slices and string projection', () => {
119+
expectSnippet(`
120+
export const selector = createSelector<[string], string>(
111121
selectUrl,
112122
url => url
113123
);
114-
`).toInfer(
115-
'selector',
116-
'MemoizedSelector<State, string, DefaultProjectorFn<string>>'
117-
);
124+
`).toInfer('selector', 'StrictMemoizedSelector<[string], string, unknown>');
118125
});
119126
});

modules/store/src/selector.ts

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,21 @@ export type ComparatorFn = (a: any, b: any) => boolean;
1717

1818
export type DefaultProjectorFn<T> = (...args: any[]) => T;
1919

20+
export type ProjectorFn<Args extends unknown[], T> = (...args: Args) => T;
21+
22+
export type StrictMemoizedSelector<
23+
Slices extends unknown[],
24+
Result,
25+
State = unknown
26+
> = MemoizedSelector<State, Result, (...slices: Slices) => Result>;
27+
2028
export interface MemoizedSelector<
2129
State,
2230
Result,
23-
ProjectorFn = DefaultProjectorFn<Result>
31+
Projector = DefaultProjectorFn<Result>
2432
> extends Selector<State, Result> {
2533
release(): void;
26-
projector: ProjectorFn;
34+
projector: Projector;
2735
setResult: (result?: Result) => void;
2836
clearResult: () => void;
2937
}
@@ -122,6 +130,22 @@ export function defaultMemoize(
122130
return { memoized, reset, setResult, clearResult };
123131
}
124132

133+
export function createSelector<
134+
State,
135+
Slices extends unknown[],
136+
Result,
137+
IsStrict extends boolean
138+
>(
139+
...args: [...Selector<State, unknown>[], unknown, unknown] &
140+
[
141+
...{ [i in keyof Slices]: Selector<State, Slices[i]> },
142+
(...s: Slices) => Result,
143+
{ strict: IsStrict }
144+
]
145+
): IsStrict extends true
146+
? StrictMemoizedSelector<Slices, Result, State>
147+
: MemoizedSelector<State, Result>;
148+
125149
export function createSelector<State, Slices extends unknown[], Result>(
126150
...args: [...Selector<State, unknown>[], unknown] &
127151
[
@@ -272,6 +296,20 @@ export function createSelector<
272296
) => Result
273297
): MemoizedSelectorWithProps<State, Props, Result>;
274298

299+
export function createSelector<
300+
State,
301+
Slices extends unknown[],
302+
Result,
303+
IsStrict extends boolean
304+
>(
305+
selectors: Selector<State, unknown>[] &
306+
[...{ [i in keyof Slices]: Selector<State, Slices[i]> }],
307+
projector: (...s: Slices) => Result,
308+
options: { strict: IsStrict }
309+
): IsStrict extends true
310+
? StrictMemoizedSelector<Slices, Result, State>
311+
: MemoizedSelector<State, Result>;
312+
275313
export function createSelector<State, Slices extends unknown[], Result>(
276314
selectors: Selector<State, unknown>[] &
277315
[...{ [i in keyof Slices]: Selector<State, Slices[i]> }],

0 commit comments

Comments
 (0)