import { IsEqual } from 'type-fest'; /** * Takes an array and returns the types that make up its parts. The prefix is * anything before the rest parameter (if any), split between it's required * part, and it's optional part. The suffix is anything after the rest * parameter (if any), and the item is the type of the rest parameter. * * NOTE: The prefix is split into 2 tuples where all items are non-optional so * that types that rely on the presence of a specific element can be built more * accurately. * * TODO: Some existing types use the `prefix` accessor which doesn't handle the optional part correctly. We need to fix each of those types before we can remove it. * * The output could be used to reconstruct the input: `[ * ...TupleParts["required"], * ...Partial["optional"]>, * ...CoercedArray["item"]>, * ...TupleParts["suffix"], * ]`. */ type TupleParts = [], PrefixOptionals extends Array = [], Suffix extends Array = []> = T extends readonly [infer Head, ...infer Tail] ? TupleParts : T extends readonly [...infer Head, infer Tail] ? TupleParts : IsTupleRestOnly extends true ? T extends ReadonlyArray ? { prefix: [...PrefixRequired, ...Partial]; required: PrefixRequired; optional: PrefixOptionals; item: Item; suffix: Suffix; } : never : T extends readonly [(infer OptionalHead)?, ...infer Tail] ? TupleParts : never; /** * Helper type for `TupleParts`. Checks if T = ReadonlyArray for some U. */ type IsTupleRestOnly = T extends readonly [] ? true : T extends readonly [unknown?, ...infer Tail] ? IsEqual, Readonly> : false; export type { TupleParts as T };