reselect-kit 1.0.1 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +307 -36
- package/dist/cjs/reselectKit.development.cjs +256 -95
- package/dist/cjs/reselectKit.development.cjs.map +1 -1
- package/dist/cjs/reselectKit.production.min.cjs +1 -1
- package/dist/cjs/reselectKit.production.min.cjs.map +1 -1
- package/dist/reselectKit.d.ts +201 -92
- package/dist/reselectKit.mjs +257 -97
- package/dist/reselectKit.mjs.map +1 -1
- package/package.json +6 -6
- package/src/__tests__/createAdaptedSelector.test.ts +3 -4
- package/src/__tests__/createBoundSelector.test.ts +98 -5
- package/src/__tests__/createChainSelector.bench.ts +117 -0
- package/src/__tests__/createChainSelector.test.ts +162 -6
- package/src/__tests__/createPathSelector.test.ts +14 -0
- package/src/__tests__/createSequenceSelector.test.ts +10 -14
- package/src/_helpers/__tests__/generateSelectorKey.test.ts +24 -0
- package/src/_helpers/__tests__/getSelectorName.test.ts +30 -0
- package/src/_helpers/unfreezeProps.ts +14 -0
- package/src/_hooks/__tests__/useSelector.bench.ts +133 -0
- package/src/_hooks/__tests__/useSelector.test.ts +69 -0
- package/src/_hooks/__tests__/useSelectors.bench.ts +160 -0
- package/src/_hooks/__tests__/useSelectors.test.ts +219 -0
- package/src/_hooks/selectorOptions.ts +11 -0
- package/src/_hooks/useSelector.ts +68 -26
- package/src/_hooks/useSelectors.ts +162 -0
- package/src/cache/__tests__/intervalMapCache.test.ts +11 -0
- package/src/createAdaptedSelector.ts +9 -5
- package/src/createBoundSelector.ts +92 -84
- package/src/createCachedSequenceSelector.ts +12 -8
- package/src/createCachedStructuredSelector.ts +11 -20
- package/src/createChainSelector.ts +134 -89
- package/src/createPathSelector.ts +71 -104
- package/src/createPropSelector.ts +9 -8
- package/src/createSequenceSelector.ts +14 -9
- package/src/index.ts +2 -0
- package/src/keys/createKeySelectorComposer.ts +12 -23
- package/src/types.ts +115 -7
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { NamedParametricSelector, NamedSelector, Path } from './types';
|
|
1
|
+
import { NamedSelector, Path } from './types';
|
|
3
2
|
import { isObject } from './_helpers/isObject';
|
|
4
3
|
import { withDebugName } from './debug/withDebugName';
|
|
5
4
|
import { getSelectorName } from './_helpers/getSelectorName';
|
|
@@ -10,131 +9,94 @@ export type IsOptional<T> = undefined extends T ? true : null extends T ? true :
|
|
|
10
9
|
|
|
11
10
|
export type IsObject<T> = T extends object ? true : false;
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
/**
|
|
13
|
+
* The selector a path builder produces. `Params` is carried through untouched
|
|
14
|
+
* from the base selector: walking a path changes the result, never the
|
|
15
|
+
* arguments, so the plain and the parametric case are the same type.
|
|
16
|
+
*/
|
|
17
|
+
export type PathSelector<S, R, Params extends readonly any[], D> = NamedSelector<
|
|
18
|
+
S,
|
|
19
|
+
R,
|
|
20
|
+
Params,
|
|
21
|
+
D
|
|
22
|
+
> & {
|
|
18
23
|
path: Path;
|
|
19
24
|
};
|
|
20
25
|
|
|
21
26
|
type Required<T> = { [P in keyof T]-?: Exclude<T[P], undefined | null> };
|
|
22
27
|
|
|
23
|
-
export type RequiredSelectorBuilder<S, R, D> = R extends object
|
|
24
|
-
? { [K in keyof R]: () => PathSelector<S, NonNullable<R[K]>, D> }
|
|
25
|
-
: {};
|
|
26
|
-
|
|
27
|
-
export type OptionalSelectorBuilder<S, R, D> = ((
|
|
28
|
-
defaultValue?: R,
|
|
29
|
-
) => PathSelector<S, R extends undefined ? Defined<R> : R, D>) &
|
|
30
|
-
(R extends object
|
|
31
|
-
? { [K in keyof Required<R>]: () => PathSelector<S, NonNullable<R[K]>, D> }
|
|
32
|
-
: {});
|
|
33
|
-
|
|
34
|
-
export type RequiredParametricSelectorBuilder<S, P, R, D> = R extends object
|
|
35
|
-
? { [K in keyof R]: () => PathParametricSelector<S, P, NonNullable<R[K]>, D> }
|
|
28
|
+
export type RequiredSelectorBuilder<S, R, Params extends readonly any[], D> = R extends object
|
|
29
|
+
? { [K in keyof R]: () => PathSelector<S, NonNullable<R[K]>, Params, D> }
|
|
36
30
|
: {};
|
|
37
31
|
|
|
38
|
-
export type
|
|
32
|
+
export type OptionalSelectorBuilder<S, R, Params extends readonly any[], D> = ((
|
|
39
33
|
defaultValue?: R,
|
|
40
|
-
) =>
|
|
34
|
+
) => PathSelector<S, R extends undefined ? Defined<R> : R, Params, D>) &
|
|
41
35
|
(R extends object
|
|
42
|
-
? { [K in keyof Required<R>]: () =>
|
|
36
|
+
? { [K in keyof Required<R>]: () => PathSelector<S, NonNullable<R[K]>, Params, D> }
|
|
43
37
|
: {});
|
|
44
38
|
|
|
45
|
-
export type RequiredObjectSelectorWrapper<S, R, D> = {
|
|
39
|
+
export type RequiredObjectSelectorWrapper<S, R, Params extends readonly any[], D> = {
|
|
46
40
|
[K in keyof R]-?: IsOptional<R[K]> extends true
|
|
47
|
-
? OptionalPathSelectorType<S, R[K], D>
|
|
48
|
-
: RequiredPathSelectorType<S, R[K], D>;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
export type OptionalObjectSelectorWrapper<S, R, D> = {
|
|
52
|
-
[K in keyof R]-?: OptionalPathSelectorType<S, R[K], D>;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
export type RequiredObjectParametricSelectorWrapper<S, P, R, D> = {
|
|
56
|
-
[K in keyof R]-?: IsOptional<R[K]> extends true
|
|
57
|
-
? OptionalPathParametricSelectorType<S, P, R[K], D>
|
|
58
|
-
: RequiredPathParametricSelectorType<S, P, R[K], D>;
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
export type OptionalObjectParametricSelectorWrapper<S, P, R, D> = {
|
|
62
|
-
[K in keyof R]-?: OptionalPathParametricSelectorType<S, P, R[K], D>;
|
|
41
|
+
? OptionalPathSelectorType<S, R[K], Params, D>
|
|
42
|
+
: RequiredPathSelectorType<S, R[K], Params, D>;
|
|
63
43
|
};
|
|
64
44
|
|
|
65
|
-
export type
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
[K: number]: IsOptional<R> extends true
|
|
69
|
-
? OptionalPathSelectorType<S, R, D>
|
|
70
|
-
: RequiredPathSelectorType<S, R, D>;
|
|
45
|
+
export type OptionalObjectSelectorWrapper<S, R, Params extends readonly any[], D> = {
|
|
46
|
+
[K in keyof R]-?: OptionalPathSelectorType<S, R[K], Params, D>;
|
|
71
47
|
};
|
|
72
48
|
|
|
73
|
-
export type
|
|
74
|
-
length: RequiredPathSelectorType<S, number, D>;
|
|
75
|
-
|
|
76
|
-
[K: number]: OptionalPathSelectorType<S, R, D>;
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
export type RequiredArrayParametricSelectorWrapper<S, P, R, D> = {
|
|
80
|
-
length: RequiredPathParametricSelectorType<S, P, number, D>;
|
|
49
|
+
export type RequiredArraySelectorWrapper<S, R, Params extends readonly any[], D> = {
|
|
50
|
+
length: RequiredPathSelectorType<S, number, Params, D>;
|
|
81
51
|
|
|
82
52
|
[K: number]: IsOptional<R> extends true
|
|
83
|
-
?
|
|
84
|
-
:
|
|
53
|
+
? OptionalPathSelectorType<S, R, Params, D>
|
|
54
|
+
: RequiredPathSelectorType<S, R, Params, D>;
|
|
85
55
|
};
|
|
86
56
|
|
|
87
|
-
export type
|
|
88
|
-
length:
|
|
57
|
+
export type OptionalArraySelectorWrapper<S, R, Params extends readonly any[], D> = {
|
|
58
|
+
length: RequiredPathSelectorType<S, number, Params, D>;
|
|
89
59
|
|
|
90
|
-
[K: number]:
|
|
60
|
+
[K: number]: OptionalPathSelectorType<S, R, Params, D>;
|
|
91
61
|
};
|
|
92
62
|
|
|
93
|
-
export type RequiredDataSelectorWrapper<
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
? OptionalArraySelectorWrapper<S, R[number], D>
|
|
101
|
-
: IsObject<R> extends true
|
|
102
|
-
? OptionalObjectSelectorWrapper<S, R, D>
|
|
103
|
-
: OptionalSelectorBuilder<S, R, D>;
|
|
104
|
-
|
|
105
|
-
export type RequiredDataParametricSelectorWrapper<S, P, R, D> = R extends unknown[]
|
|
106
|
-
? RequiredArrayParametricSelectorWrapper<S, P, R[number], D>
|
|
63
|
+
export type RequiredDataSelectorWrapper<
|
|
64
|
+
S,
|
|
65
|
+
R,
|
|
66
|
+
Params extends readonly any[],
|
|
67
|
+
D,
|
|
68
|
+
> = R extends unknown[]
|
|
69
|
+
? RequiredArraySelectorWrapper<S, R[number], Params, D>
|
|
107
70
|
: IsObject<R> extends true
|
|
108
|
-
?
|
|
109
|
-
:
|
|
71
|
+
? RequiredObjectSelectorWrapper<S, R, Params, D>
|
|
72
|
+
: RequiredSelectorBuilder<S, R, Params, D>;
|
|
110
73
|
|
|
111
|
-
export type
|
|
112
|
-
|
|
74
|
+
export type OptionalDataSelectorWrapper<
|
|
75
|
+
S,
|
|
76
|
+
R,
|
|
77
|
+
Params extends readonly any[],
|
|
78
|
+
D,
|
|
79
|
+
> = R extends unknown[]
|
|
80
|
+
? OptionalArraySelectorWrapper<S, R[number], Params, D>
|
|
113
81
|
: IsObject<R> extends true
|
|
114
|
-
?
|
|
115
|
-
:
|
|
82
|
+
? OptionalObjectSelectorWrapper<S, R, Params, D>
|
|
83
|
+
: OptionalSelectorBuilder<S, R, Params, D>;
|
|
116
84
|
|
|
117
|
-
export type RequiredPathSelectorType<
|
|
118
|
-
RequiredDataSelectorWrapper<S, NonNullable<R>, D>;
|
|
119
|
-
|
|
120
|
-
export type OptionalPathSelectorType<S, R, D> = OptionalSelectorBuilder<S, R, D> &
|
|
121
|
-
OptionalDataSelectorWrapper<S, NonNullable<R>, D>;
|
|
122
|
-
|
|
123
|
-
export type RequiredPathParametricSelectorType<S, P, R, D> = RequiredParametricSelectorBuilder<
|
|
85
|
+
export type RequiredPathSelectorType<
|
|
124
86
|
S,
|
|
125
|
-
P,
|
|
126
87
|
R,
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
88
|
+
Params extends readonly any[],
|
|
89
|
+
D,
|
|
90
|
+
> = RequiredSelectorBuilder<S, R, Params, D> &
|
|
91
|
+
RequiredDataSelectorWrapper<S, NonNullable<R>, Params, D>;
|
|
130
92
|
|
|
131
|
-
export type
|
|
93
|
+
export type OptionalPathSelectorType<
|
|
132
94
|
S,
|
|
133
|
-
P,
|
|
134
95
|
R,
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
96
|
+
Params extends readonly any[],
|
|
97
|
+
D,
|
|
98
|
+
> = OptionalSelectorBuilder<S, R, Params, D> &
|
|
99
|
+
OptionalDataSelectorWrapper<S, NonNullable<R>, Params, D>;
|
|
138
100
|
|
|
139
101
|
const defaultVoidFunction = () => {
|
|
140
102
|
return;
|
|
@@ -195,14 +157,19 @@ export const innerCreatePathSelector = (
|
|
|
195
157
|
});
|
|
196
158
|
};
|
|
197
159
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
160
|
+
/**
|
|
161
|
+
* Builds a proxy that turns property access into a selector reading that path.
|
|
162
|
+
*
|
|
163
|
+
* `Params` is inferred straight from the base selector, so the plain and the
|
|
164
|
+
* parametric case share one signature — and one set of builder types — instead
|
|
165
|
+
* of being told apart by a conditional in the parameter position. It defaults
|
|
166
|
+
* to empty so that `createPathSelector<State, Result>(selector)` keeps working
|
|
167
|
+
* for callers that spell the type arguments out.
|
|
168
|
+
*/
|
|
169
|
+
export function createPathSelector<S, R, Params extends readonly any[] = []>(
|
|
170
|
+
baseSelector: (state: S, ...params: Params) => R,
|
|
171
|
+
): IsOptional<R> extends true
|
|
172
|
+
? OptionalPathSelectorType<S, R, Params, [typeof baseSelector]>
|
|
173
|
+
: RequiredPathSelectorType<S, R, Params, [typeof baseSelector]> {
|
|
207
174
|
return innerCreatePathSelector(baseSelector as (...args: unknown[]) => unknown) as any;
|
|
208
175
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Selector } from '@veksa/reselect';
|
|
2
|
-
import { innerCreatePathSelector,
|
|
2
|
+
import { innerCreatePathSelector, RequiredPathSelectorType } from './createPathSelector';
|
|
3
3
|
import { Path } from './types';
|
|
4
4
|
|
|
5
5
|
const propSelectorSymbol = Symbol.for('PropSelector');
|
|
@@ -8,10 +8,10 @@ export const isPropSelector = (selector: unknown): selector is { path: Path } =>
|
|
|
8
8
|
return selector instanceof Object && propSelectorSymbol in selector;
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
-
export function createPropSelector<P>():
|
|
11
|
+
export function createPropSelector<P>(): RequiredPathSelectorType<
|
|
12
12
|
unknown,
|
|
13
13
|
P,
|
|
14
|
-
P,
|
|
14
|
+
[P],
|
|
15
15
|
[Selector<unknown, P, [P]>]
|
|
16
16
|
> {
|
|
17
17
|
const propsSelector = (_state: unknown, props: unknown) => props;
|
|
@@ -20,9 +20,10 @@ export function createPropSelector<P>(): RequiredPathParametricSelectorType<
|
|
|
20
20
|
Object.defineProperty(selector, propSelectorSymbol, { value: true });
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
-
return innerCreatePathSelector(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
return innerCreatePathSelector(propsSelector, [], applyMeta) as RequiredPathSelectorType<
|
|
24
|
+
unknown,
|
|
25
|
+
P,
|
|
26
|
+
[P],
|
|
27
|
+
[Selector<unknown, P, [P]>]
|
|
28
|
+
>;
|
|
28
29
|
}
|
|
@@ -1,14 +1,19 @@
|
|
|
1
|
-
import { createSelector, Selector } from '@veksa/reselect';
|
|
1
|
+
import { createSelector, Selector, SelectorResultArray } from '@veksa/reselect';
|
|
2
|
+
import { AnySelector, MergedParams, MergedState } from './types';
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Runs a group of selectors and collects their results positionally.
|
|
6
|
+
*
|
|
7
|
+
* The selectors are inferred as a tuple rather than an array, which is what
|
|
8
|
+
* makes the result a tuple of the individual result types and lets `state` and
|
|
9
|
+
* the extra arguments be merged per position. An array would collapse them into
|
|
10
|
+
* a union and resolve everything past `state` to `never`, which is why the
|
|
11
|
+
* plain and the parametric case used to need an overload each.
|
|
12
|
+
*/
|
|
13
|
+
export function createSequenceSelector<Selectors extends readonly AnySelector[]>(
|
|
14
|
+
selectors: [...Selectors],
|
|
5
15
|
selectorCreator?: typeof createSelector,
|
|
6
|
-
): Selector<
|
|
7
|
-
|
|
8
|
-
export function createSequenceSelector<S, P, R>(
|
|
9
|
-
selectors: Selector<S, R, [P]>[],
|
|
10
|
-
selectorCreator?: typeof createSelector,
|
|
11
|
-
): Selector<S, R[], [P]>;
|
|
16
|
+
): Selector<MergedState<Selectors>, SelectorResultArray<Selectors>, MergedParams<Selectors>>;
|
|
12
17
|
|
|
13
18
|
export function createSequenceSelector(selectors: any, selectorCreator = createSelector) {
|
|
14
19
|
return selectorCreator(selectors, (...results: unknown[]) => results);
|
package/src/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ export { createBoundSelector } from './createBoundSelector';
|
|
|
7
7
|
export { createEmptySelector } from './createEmptySelector';
|
|
8
8
|
export { createAdaptedSelector } from './createAdaptedSelector';
|
|
9
9
|
export { createChainSelector, type ChainSelectorOptions } from './createChainSelector';
|
|
10
|
+
export { createSequenceSelector } from './createSequenceSelector';
|
|
10
11
|
export { createCachedSequenceSelector } from './createCachedSequenceSelector';
|
|
11
12
|
export { createCachedStructuredSelector } from './createCachedStructuredSelector';
|
|
12
13
|
|
|
@@ -24,3 +25,4 @@ export { initGarbageCollector, IntervalMapCache } from './cache/intervalMapCache
|
|
|
24
25
|
export { TreeCache } from './cache/TreeCache';
|
|
25
26
|
|
|
26
27
|
export { useSelector } from './_hooks/useSelector';
|
|
28
|
+
export { useSelectors } from './_hooks/useSelectors';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { KeySelector } from '@veksa/re-reselect';
|
|
2
|
-
import {
|
|
2
|
+
import { MergedParams, MergedState } from '../types';
|
|
3
3
|
|
|
4
4
|
export const composedKeySelectorSymbol = Symbol.for('ComposedKeySelector');
|
|
5
5
|
|
|
@@ -9,39 +9,28 @@ export const composedKeySelectorSymbol = Symbol.for('ComposedKeySelector');
|
|
|
9
9
|
*/
|
|
10
10
|
type AnyKeySelector = KeySelector<any>;
|
|
11
11
|
|
|
12
|
-
/** Intersection of every input key selector's `state` argument. */
|
|
13
|
-
type ComposedState<Ks extends readonly AnyKeySelector[]> = UnionToIntersection<
|
|
14
|
-
{ [Index in keyof Ks]: Parameters<Ks[Index]>[0] }[number]
|
|
15
|
-
>;
|
|
16
|
-
|
|
17
|
-
/** Union of every input key selector's `props` argument (position 1), if any. */
|
|
18
|
-
type PropsUnion<Ks extends readonly AnyKeySelector[]> = {
|
|
19
|
-
[Index in keyof Ks]: Parameters<Ks[Index]> extends [any, infer Props, ...any[]] ? Props : never;
|
|
20
|
-
}[number];
|
|
21
|
-
|
|
22
|
-
/** Intersection of every input key selector's `props`, or `never` if none are parametric. */
|
|
23
|
-
type ComposedProps<Ks extends readonly AnyKeySelector[]> = [PropsUnion<Ks>] extends [never]
|
|
24
|
-
? never
|
|
25
|
-
: UnionToIntersection<PropsUnion<Ks>>;
|
|
26
|
-
|
|
27
12
|
/**
|
|
28
13
|
* The key selector produced by a {@link KeySelectorComposer}: a function that
|
|
29
|
-
* intersects the `state`
|
|
30
|
-
*
|
|
14
|
+
* intersects the `state` and the extra arguments of every composed key
|
|
15
|
+
* selector, tagged with the original inputs as `dependencies`.
|
|
31
16
|
*/
|
|
32
|
-
export type OutputKeySelector<
|
|
33
|
-
|
|
34
|
-
|
|
17
|
+
export type OutputKeySelector<
|
|
18
|
+
S,
|
|
19
|
+
Params extends readonly any[],
|
|
20
|
+
D extends readonly AnyKeySelector[],
|
|
21
|
+
> = ((state: S, ...params: Params) => unknown) & {
|
|
35
22
|
dependencies: D;
|
|
36
23
|
};
|
|
37
24
|
|
|
38
25
|
/**
|
|
39
26
|
* Composes N key selectors into a single one. A single variadic signature with
|
|
40
|
-
* tuple inference replaces the former per-arity overload set
|
|
27
|
+
* tuple inference replaces the former per-arity overload set; `state` and the
|
|
28
|
+
* extra arguments are merged by the same helpers every other multi-selector
|
|
29
|
+
* creator in the library uses.
|
|
41
30
|
*/
|
|
42
31
|
export type KeySelectorComposer = <Ks extends readonly AnyKeySelector[]>(
|
|
43
32
|
...keySelectors: Ks
|
|
44
|
-
) => OutputKeySelector<
|
|
33
|
+
) => OutputKeySelector<MergedState<Ks>, MergedParams<Ks>, Ks>;
|
|
45
34
|
|
|
46
35
|
export function isComposedKeySelector(
|
|
47
36
|
keySelector: AnyKeySelector,
|
package/src/types.ts
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
GetParamsFromSelectors,
|
|
3
|
+
GetStateFromSelectors,
|
|
4
|
+
Selector,
|
|
5
|
+
SelectorArray,
|
|
6
|
+
} from '@veksa/reselect';
|
|
2
7
|
import { OutputCachedSelector } from '@veksa/re-reselect';
|
|
3
8
|
|
|
9
|
+
/**
|
|
10
|
+
* The loosest shape a selector can take: a function of `state` plus any number
|
|
11
|
+
* of extra arguments. Used as the constraint for variadic tuple inference.
|
|
12
|
+
*/
|
|
13
|
+
export type AnySelector = (state: any, ...params: any[]) => any;
|
|
14
|
+
|
|
4
15
|
/**
|
|
5
16
|
* A selector carrying optional debug metadata. In the unified model a
|
|
6
17
|
* "parametric" selector is simply a selector whose `Params` tuple is non-empty,
|
|
@@ -18,12 +29,6 @@ export type NamedSelector<S, R, Params extends readonly any[] = [], D = unknown[
|
|
|
18
29
|
dependencies?: D;
|
|
19
30
|
};
|
|
20
31
|
|
|
21
|
-
/**
|
|
22
|
-
* Back-compat alias: a parametric selector is a {@link NamedSelector} whose
|
|
23
|
-
* single extra argument is `Props`.
|
|
24
|
-
*/
|
|
25
|
-
export type NamedParametricSelector<S, P, R, D = unknown[]> = NamedSelector<S, R, [P], D>;
|
|
26
|
-
|
|
27
32
|
export type ReReselectSelector = OutputCachedSelector<SelectorArray, unknown>;
|
|
28
33
|
|
|
29
34
|
export type CachedSelector = Pick<ReReselectSelector, 'cache' | 'keySelector'> &
|
|
@@ -41,3 +46,106 @@ export type UnionToIntersection<Union> = (
|
|
|
41
46
|
) extends (merged: infer Intersection) => void
|
|
42
47
|
? Intersection
|
|
43
48
|
: never;
|
|
49
|
+
|
|
50
|
+
/** The values of a group of selectors, whether it is an object or a tuple. */
|
|
51
|
+
type SelectorsUnion<Selectors> = Selectors extends readonly AnySelector[]
|
|
52
|
+
? Selectors[number]
|
|
53
|
+
: Selectors[keyof Selectors];
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The `state` argument of each selector in a union of them. Distributed over
|
|
57
|
+
* the union rather than matched against it, so each member is read on its own.
|
|
58
|
+
*/
|
|
59
|
+
type StateOf<S> = S extends AnySelector ? Parameters<S>[0] : never;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* The `props` argument of the selectors in a union that require one, or `never`
|
|
63
|
+
* for the ones that take none. The argument tuple is matched rather than the
|
|
64
|
+
* signature: a selector of `state` alone is assignable to one that also takes
|
|
65
|
+
* `props`, and would otherwise contribute `unknown`.
|
|
66
|
+
*/
|
|
67
|
+
type RequiredPropsOf<S> = S extends AnySelector
|
|
68
|
+
? Parameters<S> extends [any, infer Props, ...any[]]
|
|
69
|
+
? Props
|
|
70
|
+
: never
|
|
71
|
+
: never;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* The `props` argument of the selectors in a union that accept one without
|
|
75
|
+
* requiring it. An optional argument does not match the tuple pattern above,
|
|
76
|
+
* which is why it needs a pattern of its own; `undefined` is what the optional
|
|
77
|
+
* marker contributes and is dropped, so that intersecting the props of the
|
|
78
|
+
* group does not collapse to `never`.
|
|
79
|
+
*
|
|
80
|
+
* A selector that leaves its arguments open — `Selector<State, Result>` is
|
|
81
|
+
* `(state, ...args: any[]) => Result` — declares no props at all and must
|
|
82
|
+
* contribute nothing, or its `any` would swallow the props of every other
|
|
83
|
+
* selector in the group. It is told apart by the length of what follows
|
|
84
|
+
* `state`: an optional argument gives a finite `0 | 1`, a rest gives `number`.
|
|
85
|
+
*/
|
|
86
|
+
type OptionalPropsOf<S> = S extends AnySelector
|
|
87
|
+
? Parameters<S> extends [any, any, ...any[]]
|
|
88
|
+
? never
|
|
89
|
+
: Parameters<S> extends [any, ...infer Rest]
|
|
90
|
+
? number extends Rest['length']
|
|
91
|
+
? never
|
|
92
|
+
: Rest extends readonly []
|
|
93
|
+
? never
|
|
94
|
+
: Exclude<Rest[0], undefined>
|
|
95
|
+
: never
|
|
96
|
+
: never;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* The `state` every selector in the group accepts: the intersection of their
|
|
100
|
+
* first arguments. An empty group constrains nothing, so it reads `unknown`
|
|
101
|
+
* rather than the `never` an intersection of no members would otherwise give.
|
|
102
|
+
*/
|
|
103
|
+
export type MergedState<Selectors> = Selectors extends readonly []
|
|
104
|
+
? unknown
|
|
105
|
+
: Selectors extends readonly AnySelector[]
|
|
106
|
+
? GetStateFromSelectors<Selectors>
|
|
107
|
+
: UnionToIntersection<StateOf<SelectorsUnion<Selectors>>>;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* The props of a union of selectors, as the argument tuple that reads all of
|
|
111
|
+
* them: empty when none takes props, optional when every selector that takes
|
|
112
|
+
* them declares them optional, required as soon as one selector requires them.
|
|
113
|
+
* The props themselves are intersected, so the argument satisfies each member.
|
|
114
|
+
*/
|
|
115
|
+
type UnionProps<Union, Required = RequiredPropsOf<Union>, Optional = OptionalPropsOf<Union>> = [
|
|
116
|
+
Required,
|
|
117
|
+
] extends [never]
|
|
118
|
+
? [Optional] extends [never]
|
|
119
|
+
? []
|
|
120
|
+
: [props?: UnionToIntersection<Optional>]
|
|
121
|
+
: [props: UnionToIntersection<Required | Optional>];
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* The extra arguments the group takes beyond `state`: `[]` when no selector is
|
|
125
|
+
* parametric, `[Props]` when some are — with the `Props` of every parametric
|
|
126
|
+
* selector intersected.
|
|
127
|
+
*
|
|
128
|
+
* A tuple of selectors is merged position by position, so a selector taking
|
|
129
|
+
* more than `props` keeps its later arguments. An object is merged through the
|
|
130
|
+
* union of its values instead, which stops at `props` but costs nothing per
|
|
131
|
+
* key: the keys carry no order worth recovering, and a batch of selectors has
|
|
132
|
+
* no reason to be capped at a size a component could plausibly reach.
|
|
133
|
+
*/
|
|
134
|
+
export type MergedParams<Selectors> = Selectors extends readonly AnySelector[]
|
|
135
|
+
? GetParamsFromSelectors<Selectors>
|
|
136
|
+
: UnionProps<SelectorsUnion<Selectors>>;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* The same element-wise merge as {@link MergedParams}, for two argument tuples
|
|
140
|
+
* that are already known — the case of a step-by-step composition, where each
|
|
141
|
+
* step adds its own arguments to what the previous steps require.
|
|
142
|
+
*/
|
|
143
|
+
export type MergeParams<A extends readonly any[], B extends readonly any[]> = A extends readonly []
|
|
144
|
+
? B
|
|
145
|
+
: B extends readonly []
|
|
146
|
+
? A
|
|
147
|
+
: A extends readonly [infer AHead, ...infer ATail]
|
|
148
|
+
? B extends readonly [infer BHead, ...infer BTail]
|
|
149
|
+
? [AHead & BHead, ...MergeParams<ATail, BTail>]
|
|
150
|
+
: A
|
|
151
|
+
: B;
|