remeda
Version:
A utility library for JavaScript and Typescript.
91 lines (89 loc) • 4.28 kB
TypeScript
import { IterableContainer } from "./IterableContainer-B2PfkIAC.js";
import { RemedaTypeError } from "./RemedaTypeError-c7UuOZhv.js";
import { Or, Simplify } from "type-fest";
//#region src/internal/types/TupleParts.d.ts
/**
* Takes a tuple and returns the types that make up its parts. These parts
* follow TypeScript's only supported format for arrays/tuples:
* [<required>, <optional>, ...<rest>[], <suffix>].
*
* There are some limitations to what shapes TypeScript supports:
* tuples can only have a suffix if they also have a non-never rest element,
* **and** tuples cannot have both an optional part and a suffix; this means
* there are only 10 possible shapes for tuples:
* 1. Empty Tuples: `[]`.
* 2. Fixed Tuples: `[string, number]`.
* 3. Optional Tuples: `[string?, number?]`.
* 4. Mixed Tuples: `[string, number?]`.
* 5. Arrays: `Array<string>`.
* 6. Fixed-Prefix Arrays: `[string, ...Array<string>]`.
* 7. Optional-Prefix Arrays: `[number?, ...Array<boolean>]`.
* 8. Mixed-Prefix Arrays: `[string, number?, ...Array<boolean>]`.
* 9. Fixed-Suffix Arrays: `[...Array<string>, string]`.
* 10. Fixed-Elements Arrays: `[string, ...Array<string>, string]`.
*
* @example [
* ...TupleParts<T>["required"],
* ...Partial<TupleParts<T>["optional"]>,
* ...CoercedArray<TupleParts<T>["item"]>,
* ...TupleParts<T>["suffix"],
* ].
*/
type TupleParts<T extends IterableContainer, Prefix extends Array<unknown> = []> = T extends readonly [infer Head, ...infer Tail] ? TupleParts<Tail, [...Prefix, Head]> : Simplify<{
/**
* A fixed tuple that defines the part of the tuple where all its
* elements are required. This will always be the first part of the
* tuple and will never contain any optional or rest elements. When the
* array doesn't have a required part this will be an empty tuple
* (`[]`).
*/
required: Prefix;
} & TuplePartsWithoutRequired<T>>;
type TuplePartsWithoutRequired<T extends IterableContainer, Suffix extends Array<unknown> = []> = T extends readonly [...infer Head, infer Tail] ? TuplePartsWithoutRequired<Head, [Tail, ...Suffix]> : (Suffix extends readonly [] ? TuplePartsWithoutFixed<T> :
// When the suffix is not empty we can skip the optional part and go
{
optional: [];
} & TuplePartsRest<T>) & {
/**
* A *fixed* tuple that defines the part of a tuple **after** a non-never
* rest parameter. These could never be optional elements, and could
* never contain another rest element. When the array doesn't have a
* required part this will be an empty tuple (`[]`).
*/
suffix: Suffix;
};
type TuplePartsWithoutFixed<T extends IterableContainer, Optional extends Array<unknown> = []> = T extends readonly [(infer Head)?, ...infer Tail] ? Or<T extends readonly [] ? true : false, Array<T[number]> extends Tail ? true : false> extends true ? {
/**
* A *fixed* tuple that defines the part of a tuple where all its
* elements are suffixed with the optional operator (`?`); but with
* the optional operator removed (e.g. `[string?]` would be
* represented as `[string]`). These elements can only follow the
* `required` part (which could be empty).
* To add optional operator back wrap the result with the built-in
* `Partial` type.
* When the array doesn't have a required part this will be an empty
* tuple (`[]`).
*
* @example Partial<TupleParts<T>["optional"]>
*/
optional: Optional;
} & TuplePartsRest<T> : TuplePartsWithoutFixed<Tail, [...Optional, Head | undefined]> : RemedaTypeError<"TupleParts", "Unexpected tuple shape", {
type: never;
metadata: T;
}>;
type TuplePartsRest<T extends IterableContainer> = {
/**
* The type for the rest parameter of the tuple, if any. Unlike the
* other parts of the tuple, this is a single type and not
* represented as an array/tuple. When a tuple doesn't have a rest
* element, this will be `never`. To convert this to a matching array
* type that could be spread into a new type use the `CoercedArray`
* type which handles the `never` case correctly.
*
* @example CoercedArray<TupleParts<T>["item"]>
*/
item: T extends readonly [] ? never : T[number];
};
//#endregion
export { TupleParts };
//# sourceMappingURL=TupleParts-Dc0oO91w.d.ts.map