UNPKG

9.72 kBPlain TextView Raw
1import type { MergeParameters } from './versionedTypes'
2export type { MergeParameters } from './versionedTypes'
3
4/*
5 *
6 * Reselect Data Types
7 *
8 */
9
10/** A standard selector function, which takes three generic type arguments:
11 * @param State The first value, often a Redux root state object
12 * @param Result The final result returned by the selector
13 * @param Params All additional arguments passed into the selector
14 */
15export type Selector<
16 // The state can be anything
17 State = any,
18 // The result will be inferred
19 Result = unknown,
20 // There are either 0 params, or N params
21 Params extends never | readonly any[] = any[]
22 // If there are 0 params, type the function as just State in, Result out.
23 // Otherwise, type it as State + Params in, Result out.
24> = [Params] extends [never]
25 ? (state: State) => Result
26 : (state: State, ...params: Params) => Result
27
28/** Selectors generated by Reselect have several additional fields attached: */
29export interface OutputSelectorFields<Combiner extends UnknownFunction, Keys> {
30 /** The final function passed to `createSelector` */
31 resultFunc: Combiner
32 /** The same function, memoized */
33 memoizedResultFunc: Combiner & Keys
34 /** Returns the last result calculated by the selector */
35 lastResult: () => ReturnType<Combiner>
36 /** An array of the input selectors */
37 dependencies: SelectorArray
38 /** Counts the number of times the output has been recalculated */
39 recomputations: () => number
40 /** Resets the count of recomputations count to 0 */
41 resetRecomputations: () => number
42}
43
44/** Represents the actual selectors generated by `createSelector`.
45 * The selector is:
46 * - "a function that takes this state + params and returns a result"
47 * - plus the attached additional fields
48 */
49export type OutputSelector<
50 S extends SelectorArray,
51 Result,
52 Combiner extends UnknownFunction,
53 Params extends readonly any[] = never, // MergeParameters<S>
54 Keys = {}
55> = Selector<GetStateFromSelectors<S>, Result, Params> &
56 OutputSelectorFields<Combiner, Keys>
57
58/** A selector that is assumed to have one additional argument, such as
59 * the props from a React component
60 */
61export type ParametricSelector<State, Props, Result> = Selector<
62 State,
63 Result,
64 [Props, ...any]
65>
66
67/** A generated selector that is assumed to have one additional argument */
68export type OutputParametricSelector<
69 State,
70 Props,
71 Result,
72 Combiner extends UnknownFunction,
73 Keys = {}
74> = ParametricSelector<State, Props, Result> &
75 OutputSelectorFields<Combiner, Keys>
76
77/** An array of input selectors */
78export type SelectorArray = ReadonlyArray<Selector>
79
80/** A standard function returning true if two values are considered equal */
81export type EqualityFn = (a: any, b: any) => boolean
82
83/*
84 *
85 * Reselect Internal Types
86 *
87 */
88
89/** Extracts an array of all return types from all input selectors */
90export type SelectorResultArray<Selectors extends SelectorArray> =
91 ExtractReturnType<Selectors>
92
93/** Determines the combined single "State" type (first arg) from all input selectors */
94export type GetStateFromSelectors<S extends SelectorArray> =
95 MergeParameters<S>[0]
96
97/** Determines the combined "Params" type (all remaining args) from all input selectors */
98export type GetParamsFromSelectors<
99 S extends SelectorArray,
100 RemainingItems extends readonly unknown[] = Tail<MergeParameters<S>>
101> = RemainingItems
102
103/*
104 *
105 * Reselect Internal Utility Types
106 *
107 */
108
109/** Any function with arguments */
110export type UnknownFunction = (...args: any[]) => any
111
112/** Extract the return type from all functions as a tuple */
113export type ExtractReturnType<T extends readonly UnknownFunction[]> = {
114 [index in keyof T]: T[index] extends T[number] ? ReturnType<T[index]> : never
115}
116
117/** First item in an array */
118export type Head<T> = T extends [any, ...any[]] ? T[0] : never
119/** All other items in an array */
120export type Tail<A> = A extends [any, ...infer Rest] ? Rest : never
121
122/** Last item in an array. Recursion also enables this to work with rest syntax - where the type of rest is extracted */
123export type ReverseHead<S extends readonly unknown[][]> = Tail<S> extends [
124 unknown
125]
126 ? S
127 : Tail<S> extends readonly unknown[][]
128 ? ReverseHead<Tail<S>>
129 : never
130
131/** All elements in array except last
132 *
133 * Recursion makes this work also when rest syntax has been used
134 * Runs _ReverseTail twice, because first pass turns last element into "never", and second pass removes it.
135 **/
136export type ReverseTail<S> = _ReverseTail<_ReverseTail<S>>
137type _ReverseTail<S> = Tail<S> extends [unknown]
138 ? [Head<S>]
139 : Tail<S> extends unknown[]
140 ? [Head<S>, ..._ReverseTail<Tail<S>>]
141 : never
142
143/** Extract only numeric keys from an array type */
144export type AllArrayKeys<A extends readonly any[]> = A extends any
145 ? {
146 [K in keyof A]: K
147 }[number]
148 : never
149
150export type List<A = any> = ReadonlyArray<A>
151
152export type Has<U, U1> = [U1] extends [U] ? 1 : 0
153
154/*
155 *
156 * External/Copied Utility Types
157 *
158 */
159
160/** The infamous "convert a union type to an intersection type" hack
161 * Source: https://github.com/sindresorhus/type-fest/blob/main/source/union-to-intersection.d.ts
162 * Reference: https://github.com/microsoft/TypeScript/issues/29594
163 */
164export type UnionToIntersection<Union> =
165 // `extends unknown` is always going to be the case and is used to convert the
166 // `Union` into a [distributive conditional
167 // type](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types).
168 (
169 Union extends unknown
170 ? // The union type is used as the only argument to a function since the union
171 // of function arguments is an intersection.
172 (distributedUnion: Union) => void
173 : // This won't happen.
174 never
175 ) extends // Infer the `Intersection` type since TypeScript represents the positional
176 // arguments of unions of functions as an intersection of the union.
177 (mergedIntersection: infer Intersection) => void
178 ? Intersection
179 : never
180
181/**
182 * Assorted util types for type-level conditional logic
183 * Source: https://github.com/KiaraGrouwstra/typical
184 */
185export type Bool = '0' | '1'
186export type Obj<T> = { [k: string]: T }
187export type And<A extends Bool, B extends Bool> = ({
188 1: { 1: '1' } & Obj<'0'>
189} & Obj<Obj<'0'>>)[A][B]
190
191export type Matches<V, T> = V extends T ? '1' : '0'
192export type IsArrayType<T> = Matches<T, any[]>
193
194export type Not<T extends Bool> = { '1': '0'; '0': '1' }[T]
195export type InstanceOf<V, T> = And<Matches<V, T>, Not<Matches<T, V>>>
196export type IsTuple<T extends { length: number }> = And<
197 IsArrayType<T>,
198 InstanceOf<T['length'], number>
199>
200
201/**
202 * Code to convert a union of values into a tuple.
203 * Source: https://stackoverflow.com/a/55128956/62937
204 */
205type Push<T extends any[], V> = [...T, V]
206
207type LastOf<T> = UnionToIntersection<
208 T extends any ? () => T : never
209> extends () => infer R
210 ? R
211 : never
212
213// TS4.1+
214export type TuplifyUnion<
215 T,
216 L = LastOf<T>,
217 N = [T] extends [never] ? true : false
218> = true extends N ? [] : Push<TuplifyUnion<Exclude<T, L>>, L>
219
220/**
221 * Converts "the values of an object" into a tuple, like a type-level `Object.values()`
222 * Source: https://stackoverflow.com/a/68695508/62937
223 */
224export type ObjValueTuple<
225 T,
226 KS extends any[] = TuplifyUnion<keyof T>,
227 R extends any[] = []
228> = KS extends [infer K, ...infer KT]
229 ? ObjValueTuple<T, KT, [...R, T[K & keyof T]]>
230 : R
231
232/** Utility type to infer the type of "all params of a function except the first", so we can determine what arguments a memoize function accepts */
233export type DropFirst<T extends unknown[]> = T extends [unknown, ...infer U]
234 ? U
235 : never
236
237/**
238 * Expand an item a single level, or recursively.
239 * Source: https://stackoverflow.com/a/69288824/62937
240 */
241export type Expand<T> = T extends (...args: infer A) => infer R
242 ? (...args: Expand<A>) => Expand<R>
243 : T extends infer O
244 ? { [K in keyof O]: O[K] }
245 : never
246
247export type ExpandRecursively<T> = T extends (...args: infer A) => infer R
248 ? (...args: ExpandRecursively<A>) => ExpandRecursively<R>
249 : T extends object
250 ? T extends infer O
251 ? { [K in keyof O]: ExpandRecursively<O[K]> }
252 : never
253 : T
254
255type Identity<T> = T
256/**
257 * Another form of type value expansion
258 * Source: https://github.com/microsoft/TypeScript/issues/35247
259 */
260export type Mapped<T> = Identity<{ [k in keyof T]: T[k] }>
261
262/**
263 * Fully expand a type, deeply
264 * Source: https://github.com/millsp/ts-toolbelt (`Any.Compute`)
265 */
266
267type ComputeDeep<A, Seen = never> = A extends BuiltIn
268 ? A
269 : If2<
270 Has<Seen, A>,
271 A,
272 A extends Array<any>
273 ? A extends Array<Record<Key, any>>
274 ? Array<
275 {
276 [K in keyof A[number]]: ComputeDeep<A[number][K], A | Seen>
277 } & unknown
278 >
279 : A
280 : A extends ReadonlyArray<any>
281 ? A extends ReadonlyArray<Record<Key, any>>
282 ? ReadonlyArray<
283 {
284 [K in keyof A[number]]: ComputeDeep<A[number][K], A | Seen>
285 } & unknown
286 >
287 : A
288 : { [K in keyof A]: ComputeDeep<A[K], A | Seen> } & unknown
289 >
290
291export type If2<B extends Boolean2, Then, Else = never> = B extends 1
292 ? Then
293 : Else
294
295export type Boolean2 = 0 | 1
296
297export type Key = string | number | symbol
298
299export type BuiltIn =
300 | Function
301 | Error
302 | Date
303 | { readonly [Symbol.toStringTag]: string }
304 | RegExp
305 | Generator