UNPKG

3.52 kBTypeScriptView Raw
1import type { UnknownFunction, Expand, TuplifyUnion, Has, List, IsTuple } from '../types';
2/** Given a set of input selectors, extracts the intersected parameters to determine
3 * what values can actually be passed to all of the input selectors at once
4 * WARNING: "you are not expected to understand this" :)
5 */
6export type MergeParameters<T extends readonly UnknownFunction[], ParamsArrays extends readonly any[][] = ExtractParams<T>, TransposedArrays = Transpose<ParamsArrays>, TuplifiedArrays extends any[] = TuplifyUnion<TransposedArrays>, LongestParamsArray extends readonly any[] = LongestArray<TuplifiedArrays>> = ExpandItems<RemoveNames<{
7 [index in keyof LongestParamsArray]: LongestParamsArray[index] extends LongestParamsArray[number] ? IgnoreInvalidIntersections<IntersectAll<LongestParamsArray[index]>> : never;
8}>>;
9/** An object with no fields */
10type EmptyObject = {
11 [K in any]: never;
12};
13type IgnoreInvalidIntersections<T> = T extends EmptyObject ? never : T;
14/** Extract the parameters from all functions as a tuple */
15export type ExtractParams<T extends readonly UnknownFunction[]> = {
16 [index in keyof T]: T[index] extends T[number] ? Parameters<T[index]> : never;
17};
18/** Recursively expand all fields in an object for easier reading */
19export type ExpandItems<T extends readonly unknown[]> = {
20 [index in keyof T]: T[index] extends T[number] ? Expand<T[index]> : never;
21};
22/** Select the longer of two arrays */
23export type Longest<L extends List, L1 extends List> = L extends unknown ? L1 extends unknown ? {
24 0: L1;
25 1: L;
26}[Has<keyof L, keyof L1>] : never : never;
27/** Recurse over a nested array to locate the longest one.
28 * Acts like a type-level `reduce()`
29 */
30export type LongestArray<S extends readonly any[][]> = IsTuple<S> extends '0' ? S[0] : S extends [any[], any[]] ? Longest<S[0], S[1]> : S extends [any[], any[], ...infer Rest] ? Longest<Longest<S[0], S[1]>, Rest extends any[][] ? LongestArray<Rest> : []> : S extends [any[]] ? S[0] : never;
31/** Recursive type for intersecting together all items in a tuple, to determine
32 * the final parameter type at a given argument index in the generated selector. */
33export type IntersectAll<T extends any[]> = IsTuple<T> extends '0' ? T[0] : _IntersectAll<T>;
34type IfJustNullish<T, True, False> = [T] extends [undefined | null] ? True : False;
35/** Intersect a pair of types together, for use in parameter type calculation.
36 * This is made much more complex because we need to correctly handle cases
37 * where a function has fewer parameters and the type is `undefined`, as well as
38 * optional params or params that have `null` or `undefined` as part of a union.
39 *
40 * If the next type by itself is `null` or `undefined`, we exclude it and return
41 * the other type. Otherwise, intersect them together.
42 */
43type _IntersectAll<T, R = unknown> = T extends [infer First, ...infer Rest] ? _IntersectAll<Rest, IfJustNullish<First, R, R & First>> : R;
44/**
45 * Removes field names from a tuple
46 * Source: https://stackoverflow.com/a/63571175/62937
47 */
48type RemoveNames<T extends readonly any[]> = [any, ...T] extends [
49 any,
50 ...infer U
51] ? U : never;
52/**
53 * Transposes nested arrays
54 * Source: https://stackoverflow.com/a/66303933/62937
55 */
56type Transpose<T> = T[Extract<keyof T, T extends readonly any[] ? number : unknown>] extends infer V ? {
57 [K in keyof V]: {
58 [L in keyof T]: K extends keyof T[L] ? T[L][K] : undefined;
59 };
60} : never;
61export {};