planning
All checks were successful
Publish To Prod / deploy_and_publish (push) Successful in 35s

This commit is contained in:
2024-10-14 09:15:30 +02:00
parent bcba00a730
commit 6e64e138e2
21059 changed files with 2317811 additions and 1 deletions

171
node_modules/reselect/src/defaultMemoize.ts generated vendored Normal file
View File

@@ -0,0 +1,171 @@
import type { EqualityFn } from './types'
// Cache implementation based on Erik Rasmussen's `lru-memoize`:
// https://github.com/erikras/lru-memoize
const NOT_FOUND = 'NOT_FOUND'
type NOT_FOUND_TYPE = typeof NOT_FOUND
interface Entry {
key: unknown
value: unknown
}
interface Cache {
get(key: unknown): unknown | NOT_FOUND_TYPE
put(key: unknown, value: unknown): void
getEntries(): Entry[]
clear(): void
}
function createSingletonCache(equals: EqualityFn): Cache {
let entry: Entry | undefined
return {
get(key: unknown) {
if (entry && equals(entry.key, key)) {
return entry.value
}
return NOT_FOUND
},
put(key: unknown, value: unknown) {
entry = { key, value }
},
getEntries() {
return entry ? [entry] : []
},
clear() {
entry = undefined
}
}
}
function createLruCache(maxSize: number, equals: EqualityFn): Cache {
let entries: Entry[] = []
function get(key: unknown) {
const cacheIndex = entries.findIndex(entry => equals(key, entry.key))
// We found a cached entry
if (cacheIndex > -1) {
const entry = entries[cacheIndex]
// Cached entry not at top of cache, move it to the top
if (cacheIndex > 0) {
entries.splice(cacheIndex, 1)
entries.unshift(entry)
}
return entry.value
}
// No entry found in cache, return sentinel
return NOT_FOUND
}
function put(key: unknown, value: unknown) {
if (get(key) === NOT_FOUND) {
// TODO Is unshift slow?
entries.unshift({ key, value })
if (entries.length > maxSize) {
entries.pop()
}
}
}
function getEntries() {
return entries
}
function clear() {
entries = []
}
return { get, put, getEntries, clear }
}
export const defaultEqualityCheck: EqualityFn = (a, b): boolean => {
return a === b
}
export function createCacheKeyComparator(equalityCheck: EqualityFn) {
return function areArgumentsShallowlyEqual(
prev: unknown[] | IArguments | null,
next: unknown[] | IArguments | null
): boolean {
if (prev === null || next === null || prev.length !== next.length) {
return false
}
// Do this in a for loop (and not a `forEach` or an `every`) so we can determine equality as fast as possible.
const length = prev.length
for (let i = 0; i < length; i++) {
if (!equalityCheck(prev[i], next[i])) {
return false
}
}
return true
}
}
export interface DefaultMemoizeOptions {
equalityCheck?: EqualityFn
resultEqualityCheck?: EqualityFn
maxSize?: number
}
// defaultMemoize now supports a configurable cache size with LRU behavior,
// and optional comparison of the result value with existing values
export function defaultMemoize<F extends (...args: any[]) => any>(
func: F,
equalityCheckOrOptions?: EqualityFn | DefaultMemoizeOptions
) {
const providedOptions =
typeof equalityCheckOrOptions === 'object'
? equalityCheckOrOptions
: { equalityCheck: equalityCheckOrOptions }
const {
equalityCheck = defaultEqualityCheck,
maxSize = 1,
resultEqualityCheck
} = providedOptions
const comparator = createCacheKeyComparator(equalityCheck)
const cache =
maxSize === 1
? createSingletonCache(comparator)
: createLruCache(maxSize, comparator)
// we reference arguments instead of spreading them for performance reasons
function memoized() {
let value = cache.get(arguments)
if (value === NOT_FOUND) {
// @ts-ignore
value = func.apply(null, arguments)
if (resultEqualityCheck) {
const entries = cache.getEntries()
const matchingEntry = entries.find(entry =>
resultEqualityCheck(entry.value, value)
)
if (matchingEntry) {
value = matchingEntry.value
}
}
cache.put(arguments, value)
}
return value
}
memoized.clearCache = () => cache.clear()
return memoized as F & { clearCache: () => void }
}

268
node_modules/reselect/src/index.ts generated vendored Normal file
View File

@@ -0,0 +1,268 @@
import type {
Selector,
GetParamsFromSelectors,
OutputSelector,
SelectorArray,
SelectorResultArray,
DropFirst,
MergeParameters,
Expand,
ObjValueTuple,
Head,
Tail
} from './types'
export type {
Selector,
GetParamsFromSelectors,
GetStateFromSelectors,
OutputSelector,
EqualityFn,
SelectorArray,
SelectorResultArray,
ParametricSelector,
OutputParametricSelector,
OutputSelectorFields
} from './types'
import {
defaultMemoize,
defaultEqualityCheck,
DefaultMemoizeOptions
} from './defaultMemoize'
export { defaultMemoize, defaultEqualityCheck }
export type { DefaultMemoizeOptions }
function getDependencies(funcs: unknown[]) {
const dependencies = Array.isArray(funcs[0]) ? funcs[0] : funcs
if (!dependencies.every(dep => typeof dep === 'function')) {
const dependencyTypes = dependencies
.map(dep =>
typeof dep === 'function'
? `function ${dep.name || 'unnamed'}()`
: typeof dep
)
.join(', ')
throw new Error(
`createSelector expects all input-selectors to be functions, but received the following types: [${dependencyTypes}]`
)
}
return dependencies as SelectorArray
}
export function createSelectorCreator<
/** Selectors will eventually accept some function to be memoized */
F extends (...args: unknown[]) => unknown,
/** A memoizer such as defaultMemoize that accepts a function + some possible options */
MemoizeFunction extends (func: F, ...options: any[]) => F,
/** The additional options arguments to the memoizer */
MemoizeOptions extends unknown[] = DropFirst<Parameters<MemoizeFunction>>
>(
memoize: MemoizeFunction,
...memoizeOptionsFromArgs: DropFirst<Parameters<MemoizeFunction>>
) {
const createSelector = (...funcs: Function[]) => {
let recomputations = 0
let lastResult: unknown
// Due to the intricacies of rest params, we can't do an optional arg after `...funcs`.
// So, start by declaring the default value here.
// (And yes, the words 'memoize' and 'options' appear too many times in this next sequence.)
let directlyPassedOptions: CreateSelectorOptions<MemoizeOptions> = {
memoizeOptions: undefined
}
// Normally, the result func or "output selector" is the last arg
let resultFunc = funcs.pop()
// If the result func is actually an _object_, assume it's our options object
if (typeof resultFunc === 'object') {
directlyPassedOptions = resultFunc as any
// and pop the real result func off
resultFunc = funcs.pop()
}
if (typeof resultFunc !== 'function') {
throw new Error(
`createSelector expects an output function after the inputs, but received: [${typeof resultFunc}]`
)
}
// Determine which set of options we're using. Prefer options passed directly,
// but fall back to options given to createSelectorCreator.
const { memoizeOptions = memoizeOptionsFromArgs } = directlyPassedOptions
// Simplifying assumption: it's unlikely that the first options arg of the provided memoizer
// is an array. In most libs I've looked at, it's an equality function or options object.
// Based on that, if `memoizeOptions` _is_ an array, we assume it's a full
// user-provided array of options. Otherwise, it must be just the _first_ arg, and so
// we wrap it in an array so we can apply it.
const finalMemoizeOptions = Array.isArray(memoizeOptions)
? memoizeOptions
: ([memoizeOptions] as MemoizeOptions)
const dependencies = getDependencies(funcs)
const memoizedResultFunc = memoize(
function recomputationWrapper() {
recomputations++
// apply arguments instead of spreading for performance.
return resultFunc!.apply(null, arguments)
} as F,
...finalMemoizeOptions
)
// If a selector is called with the exact same arguments we don't need to traverse our dependencies again.
const selector = memoize(function dependenciesChecker() {
const params = []
const length = dependencies.length
for (let i = 0; i < length; i++) {
// apply arguments instead of spreading and mutate a local list of params for performance.
// @ts-ignore
params.push(dependencies[i].apply(null, arguments))
}
// apply arguments instead of spreading for performance.
lastResult = memoizedResultFunc.apply(null, params)
return lastResult
} as F)
Object.assign(selector, {
resultFunc,
memoizedResultFunc,
dependencies,
lastResult: () => lastResult,
recomputations: () => recomputations,
resetRecomputations: () => (recomputations = 0)
})
return selector
}
// @ts-ignore
return createSelector as CreateSelectorFunction<
F,
MemoizeFunction,
MemoizeOptions
>
}
export interface CreateSelectorOptions<MemoizeOptions extends unknown[]> {
memoizeOptions: MemoizeOptions[0] | MemoizeOptions
}
/**
* An instance of createSelector, customized with a given memoize implementation
*/
export interface CreateSelectorFunction<
F extends (...args: unknown[]) => unknown,
MemoizeFunction extends (func: F, ...options: any[]) => F,
MemoizeOptions extends unknown[] = DropFirst<Parameters<MemoizeFunction>>,
Keys = Expand<
Pick<ReturnType<MemoizeFunction>, keyof ReturnType<MemoizeFunction>>
>
> {
/** Input selectors as separate inline arguments */
<Selectors extends SelectorArray, Result>(
...items: [
...Selectors,
(...args: SelectorResultArray<Selectors>) => Result
]
): OutputSelector<
Selectors,
Result,
(...args: SelectorResultArray<Selectors>) => Result,
GetParamsFromSelectors<Selectors>,
Keys
> &
Keys
/** Input selectors as separate inline arguments with memoizeOptions passed */
<Selectors extends SelectorArray, Result>(
...items: [
...Selectors,
(...args: SelectorResultArray<Selectors>) => Result,
CreateSelectorOptions<MemoizeOptions>
]
): OutputSelector<
Selectors,
Result,
((...args: SelectorResultArray<Selectors>) => Result),
GetParamsFromSelectors<Selectors>,
Keys
> &
Keys
/** Input selectors as a separate array */
<Selectors extends SelectorArray, Result>(
selectors: [...Selectors],
combiner: (...args: SelectorResultArray<Selectors>) => Result,
options?: CreateSelectorOptions<MemoizeOptions>
): OutputSelector<
Selectors,
Result,
(...args: SelectorResultArray<Selectors>) => Result,
GetParamsFromSelectors<Selectors>,
Keys
> &
Keys
}
export const createSelector =
/* #__PURE__ */ createSelectorCreator(defaultMemoize)
type SelectorsObject = { [key: string]: (...args: any[]) => any }
export interface StructuredSelectorCreator {
<
SelectorMap extends SelectorsObject,
SelectorParams = MergeParameters<ObjValueTuple<SelectorMap>>
>(
selectorMap: SelectorMap,
selectorCreator?: CreateSelectorFunction<any, any, any>
): (
// Accept an arbitrary number of parameters for all selectors
// The annoying head/tail bit here is because TS isn't convinced that
// the `SelectorParams` type is really an array, so we launder things.
// Plus it matches common usage anyway.
state: Head<SelectorParams>,
...params: Tail<SelectorParams>
) => {
[Key in keyof SelectorMap]: ReturnType<SelectorMap[Key]>
}
<State, Result = State>(
selectors: { [K in keyof Result]: Selector<State, Result[K], never> },
selectorCreator?: CreateSelectorFunction<any, any, any>
): Selector<State, Result, never>
}
// Manual definition of state and output arguments
export const createStructuredSelector = ((
selectors: SelectorsObject,
selectorCreator = createSelector
) => {
if (typeof selectors !== 'object') {
throw new Error(
'createStructuredSelector expects first argument to be an object ' +
`where each property is a selector, instead received a ${typeof selectors}`
)
}
const objectKeys = Object.keys(selectors)
const resultSelector = selectorCreator(
// @ts-ignore
objectKeys.map(key => selectors[key]),
(...values: any[]) => {
return values.reduce((composition, value, index) => {
composition[objectKeys[index]] = value
return composition
}, {})
}
)
return resultSelector
}) as unknown as StructuredSelectorCreator

3325
node_modules/reselect/src/legacyTypes/ts4.1/index.d.ts generated vendored Normal file

File diff suppressed because it is too large Load Diff

305
node_modules/reselect/src/types.ts generated vendored Normal file
View File

@@ -0,0 +1,305 @@
import type { MergeParameters } from './versionedTypes'
export type { MergeParameters } from './versionedTypes'
/*
*
* Reselect Data Types
*
*/
/** A standard selector function, which takes three generic type arguments:
* @param State The first value, often a Redux root state object
* @param Result The final result returned by the selector
* @param Params All additional arguments passed into the selector
*/
export type Selector<
// The state can be anything
State = any,
// The result will be inferred
Result = unknown,
// There are either 0 params, or N params
Params extends never | readonly any[] = any[]
// If there are 0 params, type the function as just State in, Result out.
// Otherwise, type it as State + Params in, Result out.
> = [Params] extends [never]
? (state: State) => Result
: (state: State, ...params: Params) => Result
/** Selectors generated by Reselect have several additional fields attached: */
export interface OutputSelectorFields<Combiner extends UnknownFunction, Keys> {
/** The final function passed to `createSelector` */
resultFunc: Combiner
/** The same function, memoized */
memoizedResultFunc: Combiner & Keys
/** Returns the last result calculated by the selector */
lastResult: () => ReturnType<Combiner>
/** An array of the input selectors */
dependencies: SelectorArray
/** Counts the number of times the output has been recalculated */
recomputations: () => number
/** Resets the count of recomputations count to 0 */
resetRecomputations: () => number
}
/** Represents the actual selectors generated by `createSelector`.
* The selector is:
* - "a function that takes this state + params and returns a result"
* - plus the attached additional fields
*/
export type OutputSelector<
S extends SelectorArray,
Result,
Combiner extends UnknownFunction,
Params extends readonly any[] = never, // MergeParameters<S>
Keys = {}
> = Selector<GetStateFromSelectors<S>, Result, Params> &
OutputSelectorFields<Combiner, Keys>
/** A selector that is assumed to have one additional argument, such as
* the props from a React component
*/
export type ParametricSelector<State, Props, Result> = Selector<
State,
Result,
[Props, ...any]
>
/** A generated selector that is assumed to have one additional argument */
export type OutputParametricSelector<
State,
Props,
Result,
Combiner extends UnknownFunction,
Keys = {}
> = ParametricSelector<State, Props, Result> &
OutputSelectorFields<Combiner, Keys>
/** An array of input selectors */
export type SelectorArray = ReadonlyArray<Selector>
/** A standard function returning true if two values are considered equal */
export type EqualityFn = (a: any, b: any) => boolean
/*
*
* Reselect Internal Types
*
*/
/** Extracts an array of all return types from all input selectors */
export type SelectorResultArray<Selectors extends SelectorArray> =
ExtractReturnType<Selectors>
/** Determines the combined single "State" type (first arg) from all input selectors */
export type GetStateFromSelectors<S extends SelectorArray> =
MergeParameters<S>[0]
/** Determines the combined "Params" type (all remaining args) from all input selectors */
export type GetParamsFromSelectors<
S extends SelectorArray,
RemainingItems extends readonly unknown[] = Tail<MergeParameters<S>>
> = RemainingItems
/*
*
* Reselect Internal Utility Types
*
*/
/** Any function with arguments */
export type UnknownFunction = (...args: any[]) => any
/** Extract the return type from all functions as a tuple */
export type ExtractReturnType<T extends readonly UnknownFunction[]> = {
[index in keyof T]: T[index] extends T[number] ? ReturnType<T[index]> : never
}
/** First item in an array */
export type Head<T> = T extends [any, ...any[]] ? T[0] : never
/** All other items in an array */
export type Tail<A> = A extends [any, ...infer Rest] ? Rest : never
/** Last item in an array. Recursion also enables this to work with rest syntax - where the type of rest is extracted */
export type ReverseHead<S extends readonly unknown[][]> = Tail<S> extends [
unknown
]
? S
: Tail<S> extends readonly unknown[][]
? ReverseHead<Tail<S>>
: never
/** All elements in array except last
*
* Recursion makes this work also when rest syntax has been used
* Runs _ReverseTail twice, because first pass turns last element into "never", and second pass removes it.
**/
export type ReverseTail<S> = _ReverseTail<_ReverseTail<S>>
type _ReverseTail<S> = Tail<S> extends [unknown]
? [Head<S>]
: Tail<S> extends unknown[]
? [Head<S>, ..._ReverseTail<Tail<S>>]
: never
/** Extract only numeric keys from an array type */
export type AllArrayKeys<A extends readonly any[]> = A extends any
? {
[K in keyof A]: K
}[number]
: never
export type List<A = any> = ReadonlyArray<A>
export type Has<U, U1> = [U1] extends [U] ? 1 : 0
/*
*
* External/Copied Utility Types
*
*/
/** The infamous "convert a union type to an intersection type" hack
* Source: https://github.com/sindresorhus/type-fest/blob/main/source/union-to-intersection.d.ts
* Reference: https://github.com/microsoft/TypeScript/issues/29594
*/
export type UnionToIntersection<Union> =
// `extends unknown` is always going to be the case and is used to convert the
// `Union` into a [distributive conditional
// type](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types).
(
Union extends unknown
? // The union type is used as the only argument to a function since the union
// of function arguments is an intersection.
(distributedUnion: Union) => void
: // This won't happen.
never
) extends // Infer the `Intersection` type since TypeScript represents the positional
// arguments of unions of functions as an intersection of the union.
(mergedIntersection: infer Intersection) => void
? Intersection
: never
/**
* Assorted util types for type-level conditional logic
* Source: https://github.com/KiaraGrouwstra/typical
*/
export type Bool = '0' | '1'
export type Obj<T> = { [k: string]: T }
export type And<A extends Bool, B extends Bool> = ({
1: { 1: '1' } & Obj<'0'>
} & Obj<Obj<'0'>>)[A][B]
export type Matches<V, T> = V extends T ? '1' : '0'
export type IsArrayType<T> = Matches<T, any[]>
export type Not<T extends Bool> = { '1': '0'; '0': '1' }[T]
export type InstanceOf<V, T> = And<Matches<V, T>, Not<Matches<T, V>>>
export type IsTuple<T extends { length: number }> = And<
IsArrayType<T>,
InstanceOf<T['length'], number>
>
/**
* Code to convert a union of values into a tuple.
* Source: https://stackoverflow.com/a/55128956/62937
*/
type Push<T extends any[], V> = [...T, V]
type LastOf<T> = UnionToIntersection<
T extends any ? () => T : never
> extends () => infer R
? R
: never
// TS4.1+
export type TuplifyUnion<
T,
L = LastOf<T>,
N = [T] extends [never] ? true : false
> = true extends N ? [] : Push<TuplifyUnion<Exclude<T, L>>, L>
/**
* Converts "the values of an object" into a tuple, like a type-level `Object.values()`
* Source: https://stackoverflow.com/a/68695508/62937
*/
export type ObjValueTuple<
T,
KS extends any[] = TuplifyUnion<keyof T>,
R extends any[] = []
> = KS extends [infer K, ...infer KT]
? ObjValueTuple<T, KT, [...R, T[K & keyof T]]>
: R
/** 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 */
export type DropFirst<T extends unknown[]> = T extends [unknown, ...infer U]
? U
: never
/**
* Expand an item a single level, or recursively.
* Source: https://stackoverflow.com/a/69288824/62937
*/
export type Expand<T> = T extends (...args: infer A) => infer R
? (...args: Expand<A>) => Expand<R>
: T extends infer O
? { [K in keyof O]: O[K] }
: never
export type ExpandRecursively<T> = T extends (...args: infer A) => infer R
? (...args: ExpandRecursively<A>) => ExpandRecursively<R>
: T extends object
? T extends infer O
? { [K in keyof O]: ExpandRecursively<O[K]> }
: never
: T
type Identity<T> = T
/**
* Another form of type value expansion
* Source: https://github.com/microsoft/TypeScript/issues/35247
*/
export type Mapped<T> = Identity<{ [k in keyof T]: T[k] }>
/**
* Fully expand a type, deeply
* Source: https://github.com/millsp/ts-toolbelt (`Any.Compute`)
*/
type ComputeDeep<A, Seen = never> = A extends BuiltIn
? A
: If2<
Has<Seen, A>,
A,
A extends Array<any>
? A extends Array<Record<Key, any>>
? Array<
{
[K in keyof A[number]]: ComputeDeep<A[number][K], A | Seen>
} & unknown
>
: A
: A extends ReadonlyArray<any>
? A extends ReadonlyArray<Record<Key, any>>
? ReadonlyArray<
{
[K in keyof A[number]]: ComputeDeep<A[number][K], A | Seen>
} & unknown
>
: A
: { [K in keyof A]: ComputeDeep<A[K], A | Seen> } & unknown
>
export type If2<B extends Boolean2, Then, Else = never> = B extends 1
? Then
: Else
export type Boolean2 = 0 | 1
export type Key = string | number | symbol
export type BuiltIn =
| Function
| Error
| Date
| { readonly [Symbol.toStringTag]: string }
| RegExp
| Generator

1
node_modules/reselect/src/versionedTypes/index.ts generated vendored Normal file
View File

@@ -0,0 +1 @@
export { MergeParameters } from './ts47-mergeParameters'

View File

@@ -0,0 +1,14 @@
{
"typesVersions": {
">=4.7": {
"index": [
"./ts47-mergeParameters.d.ts"
]
},
"<4.7": {
"index": [
"./ts46-mergeParameters.d.ts"
]
}
}
}

View File

@@ -0,0 +1,171 @@
import type {
UnknownFunction,
Expand,
TuplifyUnion,
Has,
List,
IsTuple
} from '../types'
/** Given a set of input selectors, extracts the intersected parameters to determine
* what values can actually be passed to all of the input selectors at once
* WARNING: "you are not expected to understand this" :)
*/
export type MergeParameters<
// The actual array of input selectors
T extends readonly UnknownFunction[],
// Given those selectors, we do several transformations on the types in sequence:
// 1) Extract "the type of parameters" for each input selector, so that we now have
// a tuple of all those parameters
ParamsArrays extends readonly any[][] = ExtractParams<T>,
// 2) Transpose the parameter tuples.
// Originally, we have nested arrays with "all params from input", "from input 2", etc:
// `[ [i1a, i1b, i1c], [i2a, i2b, i2c], [i3a, i3b, i3c] ],
// In order to intersect the params at each index, we need to transpose them so that
// we have "all the first args", "all the second args", and so on:
// `[ [i1a, i2a, i3a], [i1b, i2b, i3b], [i1c, i2c, i3c] ]
// Unfortunately, this step also turns the arrays into a union, and weirder, it is
// a union of all possible combinations for all input functions, so there's duplicates.
TransposedArrays = Transpose<ParamsArrays>,
// 3) Turn the union of arrays back into a nested tuple. Order does not matter here.
TuplifiedArrays extends any[] = TuplifyUnion<TransposedArrays>,
// 4) Find the longest params array out of the ones we have.
// Note that this is actually the _nested_ data we wanted out of the transpose step,
// so it has all the right pieces we need.
LongestParamsArray extends readonly any[] = LongestArray<TuplifiedArrays>
> =
// After all that preparation work, we can actually do parameter extraction.
// These steps work somewhat inside out (jump ahead to the middle):
// 11) Finally, after all that, run a shallow expansion on the values to make the user-visible
// field details more readable when viewing the selector's type in a hover box.
ExpandItems<
// 10) Tuples can have field names attached, and it seems to work better to remove those
RemoveNames<{
// 5) We know the longest params array has N args. Loop over the indices of that array.
// 6) For each index, do a check to ensure that we're _only_ checking numeric indices,
// not any field names for array functions like `slice()`
[index in keyof LongestParamsArray]: LongestParamsArray[index] extends LongestParamsArray[number]
? // 9) Any object types that were intersected may have had
IgnoreInvalidIntersections<
// 8) Then, intersect all of the parameters for this arg together.
IntersectAll<
// 7) Since this is a _nested_ array, extract the right sub-array for this index
LongestParamsArray[index]
>
>
: never
}>
>
/*
*
* Reselect Internal Utility Types
*
*/
/*
*
* Reselect Internal Utility Types
*
*/
/** An object with no fields */
type EmptyObject = {
[K in any]: never
}
type IgnoreInvalidIntersections<T> = T extends EmptyObject ? never : T
/** Extract the parameters from all functions as a tuple */
export type ExtractParams<T extends readonly UnknownFunction[]> = {
[index in keyof T]: T[index] extends T[number] ? Parameters<T[index]> : never
}
/** Recursively expand all fields in an object for easier reading */
export type ExpandItems<T extends readonly unknown[]> = {
[index in keyof T]: T[index] extends T[number] ? Expand<T[index]> : never
}
/** Select the longer of two arrays */
export type Longest<L extends List, L1 extends List> = L extends unknown
? L1 extends unknown
? { 0: L1; 1: L }[Has<keyof L, keyof L1>]
: never
: never
/** Recurse over a nested array to locate the longest one.
* Acts like a type-level `reduce()`
*/
export type LongestArray<S extends readonly any[][]> =
// If this isn't a tuple, all indices are the same, we can't tell a difference
IsTuple<S> extends '0'
? // so just return the type of the first item
S[0]
: // If there's two nested arrays remaining, compare them
S extends [any[], any[]]
? Longest<S[0], S[1]>
: // If there's more than two, extract their types, treat the remainder as a smaller array
S extends [any[], any[], ...infer Rest]
? // then compare those two, recurse through the smaller array, and compare vs its result
Longest<
Longest<S[0], S[1]>,
Rest extends any[][] ? LongestArray<Rest> : []
>
: // If there's one item left, return it
S extends [any[]]
? S[0]
: never
/** Recursive type for intersecting together all items in a tuple, to determine
* the final parameter type at a given argument index in the generated selector. */
export type IntersectAll<T extends any[]> = IsTuple<T> extends '0'
? T[0]
: _IntersectAll<T>
type IfJustNullish<T, True, False> = [T] extends [undefined | null]
? True
: False
/** Intersect a pair of types together, for use in parameter type calculation.
* This is made much more complex because we need to correctly handle cases
* where a function has fewer parameters and the type is `undefined`, as well as
* optional params or params that have `null` or `undefined` as part of a union.
*
* If the next type by itself is `null` or `undefined`, we exclude it and return
* the other type. Otherwise, intersect them together.
*/
type _IntersectAll<T, R = unknown> = T extends [infer First, ...infer Rest]
? _IntersectAll<Rest, IfJustNullish<First, R, R & First>>
: R
/*
*
* External/Copied Utility Types
*
*/
/**
* Removes field names from a tuple
* Source: https://stackoverflow.com/a/63571175/62937
*/
type RemoveNames<T extends readonly any[]> = [any, ...T] extends [
any,
...infer U
]
? U
: never
/**
* Transposes nested arrays
* Source: https://stackoverflow.com/a/66303933/62937
*/
type Transpose<T> = T[Extract<
keyof T,
T extends readonly any[] ? number : unknown
>] extends infer V
? {
[K in keyof V]: {
[L in keyof T]: K extends keyof T[L] ? T[L][K] : undefined
}
}
: never

View File

@@ -0,0 +1,66 @@
// This entire implementation courtesy of Anders Hjelsberg:
// https://github.com/microsoft/TypeScript/pull/50831#issuecomment-1253830522
import { ReverseHead, ReverseTail } from '../types'
type UnknownFunction = (...args: any[]) => any
type LongestTuple<T> = T extends [infer U extends unknown[]]
? U
: T extends [infer U, ...infer R extends unknown[][]]
? MostProperties<U, LongestTuple<R>>
: never
type MostProperties<T, U> = keyof U extends keyof T ? T : U
type ElementAt<T, N extends keyof any> = N extends keyof T ? T[N] : unknown
type ElementsAt<T, N extends keyof any> = {
[K in keyof T]: ElementAt<T[K], N>
}
type Intersect<T extends readonly unknown[]> = T extends []
? unknown
: T extends [infer H, ...infer T]
? H & Intersect<T>
: T[number]
type MergeTuples<T, L extends unknown[] = LongestTuple<T>> = {
[K in keyof L]: Intersect<
ElementsAt<T, K> extends readonly unknown[] ? ElementsAt<T, K> : never
>
}
type ExtractParameters<T extends readonly UnknownFunction[]> = {
[K in keyof T]: Parameters<T[K]>
}
export type MergeParameters<T extends readonly UnknownFunction[]> =
'0' extends keyof T
? MergeTuples<MakeRestExplicit<ExtractParameters<T>>>
: Parameters<T[number]>
type HasRest<S extends readonly unknown[]> = number extends S['length']
? true
: false
type HasExplicit<S extends readonly unknown[]> = '0' extends keyof S
? true
: false
type HasCombined<S extends readonly unknown[]> = true extends HasExplicit<S> &
HasRest<S>
? true
: false
type MakeRestExplicit<T extends readonly unknown[][]> =
true extends HasCombined<T>
? [
...ReverseTail<T>,
ReverseHead<T> extends readonly unknown[]
? ReverseHead<T>[number]
: never
]
: true extends HasRest<T>
? [...T]
: T