import { Numbers as N, Numbers } from "../numbers/Numbers"; import { Apply, args, Call, Fn, PartialApply, Pipe, unset, _ } from "../core/Core"; import { Iterator, Prettify, Stringifiable } from "../helpers"; import { Objects } from "../objects/Objects"; import * as NumberImpls from "../numbers/impl/numbers"; import { Std } from "../std/Std"; export declare namespace Tuples { type HeadImpl = xs extends readonly [infer head, ...any] ? head : never; /** * Get an element from a tuple at a given index. * @param args[0] - The index of the element to get. * @param args[1] - The tuple to get the element from. * @param index - The index of the element to get. * @param tuple - The tuple to get the element from. * @returns The element at the specified index. * @example * ```ts * type T0 = Call; // "b" * type T1 = Call>; // "b" * type T2 = Call, ["a", "b", "c"]>; // "b" * ``` */ export type At = PartialApply; interface AtFn extends Fn { return: Extract[Extract]; } type IsEmptyImpl = [] extends tuple ? true : false; interface IsEmptyFn extends Fn { return: IsEmptyImpl>; } /** * Check if a tuple is empty. * @param args[0] - The tuple to check. * @param tuple - The tuple to check. * @returns `true` if the tuple is empty, `false` otherwise. * @example * ```ts * type T0 = Call; // true * type T1 = Call; // false * type T2 = Call>; // true * ``` */ export type IsEmpty = PartialApply; interface ToUnionFn extends Fn { return: this["arg0"][number]; } /** * Convert a tuple to a union of its elements. * @param tuple - The tuple to convert. * @returns A union of the tuple's elements. * @example * ```ts * type T0 = Call; // 1 | 2 | 3 * type T1 = Call>; // 1 | 2 | 3 * ``` */ export type ToUnion = PartialApply; /** * `Unions.ToIntersection` turns a tuple into an intersection type. * @param tuple - any tuple. * @returns an intersection of all member of the tuple * @example * ```ts * type T0 = Call; // {a: string} & {b: number} * ``` */ export type ToIntersection = PartialApply; interface ToIntersectionFn extends Fn { return: this["args"] extends [infer tuples extends readonly any[], ...any] ? Call> : never; } interface IntersectFn extends Fn { return: this["arg0"] & this["arg1"]; } /** * Returns the first element of a tuple. * @params args[0] - A tuple. * @return The first element of a tuple. * @example * ```ts * type T0 = Call; // 1 * type T1 = Call; // never * type T2 = Call; // 1 * ``` */ export type Head = PartialApply; interface HeadFn extends Fn { return: HeadImpl; } type TailImpl = xs extends readonly [any, ...infer tail] ? tail : []; /** * Returns a tuple with all elements except the first. * @params args[0] - A tuple. * @return A tuple with all elements except the first. * @example * ```ts * type T0 = Call; // [2, 3] * type T1 = Call; // [] * type T2 = Call; // [] * ``` */ export type Tail = PartialApply; export interface TailFn extends Fn { return: TailImpl; } type LastImpl = xs extends readonly [...any, infer last] ? last : never; /** * Returns the last element of a tuple. * @params args[0] - A tuple. * @return The last element of a tuple. * @example * ```ts * type T0 = Call; // 3 * type T1 = Call; // never * type T2 = Call; // 1 * ``` */ export type Last = PartialApply; export interface LastFn extends Fn { return: LastImpl; } /** * Apply a function to each element of a tuple and return a new tuple with the results. * @params args[0] - A tuple of elements to be transformed. * @param fn - A function that takes an element of the tuple and transforms it. * @returns A tuple with the results of applying the function to each element of the input tuple. * @example * ```ts * type T0 = Call,[1,2,3]>; // ["1","2","3"] * type T1 = Call,[]>; // [] * ``` */ export type Map = PartialApply; interface MapFn extends Fn { return: this["args"] extends [ infer fn extends Fn, infer tuple extends unknown[] ] ? { [key in keyof tuple]: Call; } : never; } interface FlatMapReducer extends Fn { return: this["args"] extends [infer acc extends any[], infer item] ? [...acc, ...Extract, readonly any[]>] : never; } /** * Apply a function to each element of a tuple and return a new tuple with the results flattened by one level. * @params args[0] - A tuple of elements to be transformed. * @param fn - A function that takes an element of the tuple and transforms it. * @returns A tuple with the results of applying the function to each element of the input tuple flattened by one level. * @example * ```ts * type T0 = Call,["hello","world"]>; // ["h","e","l","l","o","w","o","r","l","d"] * type T1 = Call,[]>; // [] * ``` */ export type FlatMap = PartialApply; interface FlatMapFn extends Fn { return: ReduceImpl>, [ ], this["arg1"]>; } type ReduceImpl = xs extends [ infer first, ...infer rest ] ? ReduceImpl, rest> : xs extends readonly [infer first, ...infer rest] ? ReduceImpl, rest> : acc; /** * Apply a reducer function to each element of a tuple starting from the first and return the accumulated result. * @params args[0] - A tuple of elements to be transformed. * @params fn - A reducer function that takes the accumulated result and the current element and returns a new accumulated result. * @params init - The initial value of the accumulated result. * @returns The accumulated result. * @example * ```ts * type T0 = Call,[1,2,3]>; // 6 * type T1 = Call,[]>; // 0 * ``` */ export type Reduce = PartialApply; interface ReduceFn extends Fn { return: ReduceImpl, this["arg1"], this["arg2"]>; } type ReverseImpl = any[] extends tuple ? tuple : ReverseRecImpl; type ReverseRecImpl = tuple extends [ infer first, ...infer rest ] ? ReverseRecImpl : acc; /** * Reverse a tuple. * @params args[0] - A tuple. * @return Reversed tuple. * @example * ```ts * type T0 = Call; // [3,2,1] * ``` */ export type Reverse = PartialApply; interface ReverseFn extends Fn { return: ReverseImpl; } type ReduceRightImpl = xs extends [ ...infer rest, infer last ] ? ReduceRightImpl, fn> : acc; /** * Apply a reducer function to each element of a tuple starting from the last and return the accumulated result. * @params args[0] - A tuple of elements to be transformed. * @params fn - A reducer function that takes the accumulated result and the current element and returns a new accumulated result. * @params init - The initial value of the accumulated result. * @returns The accumulated result. * @example * ```ts * type T0 = Call,[1,2,3]>; // 6 * type T1 = Call,[]>; // 0 * ``` */ export type ReduceRight = PartialApply; interface ReduceRightFn extends Fn { return: ReduceRightImpl>; } interface FilterReducer extends Fn { return: this["args"] extends [infer acc extends any[], infer item] ? Call extends true ? [...acc, item] : acc : never; } /** * Apply a predicate function to each element of a tuple and return a new tuple with the elements that satisfy the predicate. * @params args[0] - A tuple of elements to be filtered. * @param fn - A predicate function that takes an element of the tuple and returns a boolean. * @returns A tuple with the elements that satisfy the predicate. * @example * ```ts * type T0 = Call>,[1,2,"3"]>; // ["3"] * type T1 = Call>,[]>; // [] * ``` */ export type Filter = PartialApply; export interface FilterFn extends Fn { return: ReduceImpl>, [ ], this["arg1"]>; } type FindImpl = xs extends [ infer first, ...infer rest ] ? Call extends true ? first : FindImpl : never; /** * Apply a predicate function to each element of a tuple and return the first element that satisfies the predicate. * @params args[0] - A tuple of elements to be filtered. * @param fn - A predicate function that takes an element of the tuple and returns a boolean. * @returns The first element that satisfies the predicate. * @example * ```ts * type T0 = Call>,[1,2,"3",4,"5"]>; // "3" * type T1 = Call>,[1,2]>; // never * ``` */ export type Find = PartialApply; export interface FindFn extends Fn { return: FindImpl>; } /** * Sum the elements of a tuple of numbers. * @params args[0] - A tuple of numbers. * @returns The sum of the elements of the tuple. * @example * ```ts * type T0 = Call; // 6 * type T1 = Call; // 0 * ``` */ export type Sum = PartialApply; interface SumFn extends Fn { return: ReduceImpl; } type DropImpl = Iterator.Get extends 0 ? xs : xs extends readonly [any, ...infer tail] ? DropImpl> : []; /** * Drop the first n elements of a tuple. * @params args[0] - A tuple of elements. * @params n - The number of elements to drop. * @returns A tuple with the first n elements dropped. * @example * ```ts * type T0 = Call,[1,2,3,4]>; // [3,4] * type T1 = Call,[1,2]>; // [] * type T2 = Call,[]>; // [] * ``` */ export type Drop = PartialApply; export interface DropFn extends Fn { return: this["args"] extends [ infer N extends number, infer T extends readonly any[] ] ? DropImpl> : never; } type TakeImpl = Iterator.Get extends 0 ? output : xs extends readonly [infer head, ...infer tail] ? TakeImpl, [...output, head]> : output; /** * Take the first n elements of a tuple. * @params args[0] - A tuple of elements. * @params n - The number of elements to take. * @returns A tuple with the first n elements. * @example * ```ts * type T0 = Call,[1,2,3,4]>; // [1,2] * type T1 = Call,[1,2]>; // [1,2] * type T2 = Call,[]>; // [] * ``` */ export type Take = PartialApply; interface TakeFn extends Fn { return: this["args"] extends [ infer N extends number, infer T extends readonly any[] ] ? TakeImpl> : never; } type TakeWhileImpl = xs extends readonly [infer head, ...infer tail] ? Call extends true ? TakeWhileImpl : output : output; /** * Take the first elements of a tuple that satisfy a predicate function. * @params args[0] - A tuple of elements. * @param fn - A predicate function that takes an element of the tuple and returns a boolean. * @returns A tuple with the first elements that satisfy the predicate. * @example * ```ts * type T0 = Call>,[1,2,"3",4,"5"]>; // [1,2] * type T1 = Call>,["1", 2]>; // [] * ``` */ export type TakeWhile = PartialApply; export interface TakeWhileFn extends Fn { return: TakeWhileImpl, Extract>; } /** * Check if a tuple staisfies a predicate function for at least one element. * @params args[0] - A tuple of elements. * @param fn - A predicate function that takes an element of the tuple and returns a boolean. * @returns A boolean indicating whether the predicate is satisfied by at least one element. * @example * ```ts * type T0 = Call>,[1,2,"3",4,"5"]>; // true * type T1 = Call>,["1", "2"]>; // false * ``` */ export type Some = PartialApply; export interface SomeFn extends Fn { return: true extends Call>, this["arg1"]>[number] ? true : false; } /** * Check if a tuple staisfies a predicate function for all elements. * @params args[0] - A tuple of elements. * @param fn - A predicate function that takes an element of the tuple and returns a boolean. * @returns A boolean indicating whether the predicate is satisfied by all elements. * @example * ```ts * type T0 = Call>,[1,2,"3",4,"5"]>; // false * type T1 = Call>,["1", "2"]>; // false * type T2 = Call>,[1, 2]>; // true * ``` */ export type Every = PartialApply; export interface EveryFn extends Fn { return: false extends Call>, this["arg1"]>[number] ? false : true; } type SortImpl = xs extends [ infer head, ...infer tail ] ? Call, tail>> extends [infer left extends any[], infer right extends any[]] ? [...SortImpl, head, ...SortImpl] : never : []; /** * Sort a tuple. * @param args[0] - The tuple to sort. * @param predicateFn - The predicate function to use for sorting. should compare 2 items and return a boolean. * @returns The sorted tuple. * @example * ```ts * type T0 = Call; // [1,2,3] * type T1 = Call,["b","c","a"]>; // ["a","b","c"] * ``` */ export interface Sort extends Fn { return: this["args"] extends [infer xs extends any[]] ? SortImpl : never; } interface JoinReducer extends Fn { return: this["args"] extends [ infer acc extends Stringifiable, infer item extends Stringifiable ] ? `${acc extends "" ? "" : `${acc}${sep}`}${item}` : never; } /** * Join a tuple into a single string. * @param args[0] - The tuple to join. * @param sep - The separator to join the strings with. * @returns The joined string. * @example * ```ts * type T0 = Call,["a","b","c"]>; // "a,b,c" * type T1 = Call; // "a,b,c" * type T2 = Call>; // "a,b,c" * ``` */ export type Join = PartialApply; interface JoinFn extends Fn { return: this["args"] extends [infer Sep extends string, infer Tuple] ? ReduceImpl, "", Tuple> : never; } /** * Adds a new element to the start of a tuple * @param args[0] - The tuple to update. * @param element - The element to add to our tuple * @returns The updated tuple. * @example * ```ts * type T0 = Call, ["a", "b", "c"]>; // ["new", "a", "b", "c"] * ``` */ export type Prepend = PartialApply; interface PrependFn extends Fn { return: this["args"] extends [infer element, infer tuple extends any[]] ? [element, ...tuple] : never; } /** * Adds a new element to the end of a tuple * @param args[0] - The tuple to update. * @param element - The element to add to our tuple * @returns The updated tuple. * @example * ```ts * type T0 = Call, ["a", "b", "c"]>; // ["a", "b", "c", "new"] * ``` */ export type Append = PartialApply; interface AppendFn extends Fn { return: this["args"] extends [infer element, infer tuple extends any[]] ? [...tuple, element] : never; } /** * Concatenate two tuples together * @param tuple1 - A list of types * @param tuple2 - Another list of types * @returns [...tuple1, ...tuple2] * @example * ```ts * type T0 = Call; // [1, 2, 3] * ``` */ export type Concat = PartialApply; interface ConcatFn extends Fn { return: this["args"] extends [ infer t1 extends readonly any[], infer t2 extends readonly any[], ...any ] ? [...t1, ...t2] : never; } /** * Splits a tuple into two groups based on a predicate: * - The first group contains elements predicate returns true for. * - The second group contains elements predicate returns false for. * * @param predicate - The tuple to update. * @param element - The element to add to our tuple * @returns - a tuple containing two tuples: one for each groupe * @example * ```ts * type T0 = Call>, [1, "a", 2, "b", 3, "c"]>; * // ^? [[1, 2, 3], ["a", "b", "c"]] * ``` */ export type Partition = PartialApply; type PartitionImpl = tuple extends [infer first, ...infer rest] ? Call extends true ? PartitionImpl : PartitionImpl : [left, right]; interface PartitionFn extends Fn { return: PartitionImpl, Extract>; } /** * SplitAt takes an index and a tuple, splits the tuple * at the provided index and returns the list of elements * before this index and the list of elements after this * index as a [before[], after[]] tuple. * * @param index - the index at which to split the list * @param tuple - The list to split * @returns A [before[], after[]] tuple. * @example * ```ts * type T0 = Call, [1, 2, 3, 4]>; // [[1, 2], [3, 4]] * type T1 = Call, [1]>; // [[1], []] * ``` */ export type SplitAt = PartialApply; export interface SplitAtFn extends Fn { return: this["args"] extends [ infer index extends number, infer tuple extends any[], ...any ] ? [ TakeImpl>, DropImpl> ] : never; } interface ZipWithMapper extends Fn { return: this["args"] extends [infer Index extends number, ...any] ? Apply, arrs>>> : never; } interface ZipWithFn extends Fn { return: this["args"] extends infer arrays extends unknown[][] ? Pipe>, Tuples.Min, Numbers.Abs, Numbers.Sub<_, 1>, Tuples.Range<0, _>, Tuples.Map> ]> : never; } /** * Zip two tuples together. * @param args[0] - The first tuple to zip. * @param args[1] - The second tuple to zip. * @param arr1 - The first tuple to zip. * @param arr2 - The second tuple to zip. * @returns The zipped tuple. * @example * ```ts * type T0 = Call; // [[1, 10], [2, 2], [3, 5]] * type T1 = Call>; // [[1, 10], [2, 2], [3, 5]] * ``` */ export type Zip = PartialApply, [ arr0, arr1, arr2, arr3, arr4, arr5, arr6, arr7, arr8, arr9 ]>; /** * Zip two tuples together using a function. * @description The function should take a 2 elements and return a value. * Using the identity function will return a 2-tuple and have the same effect as `Zip`. * @param args[0] - The first tuple to zip. * @param args[1] - The second tuple to zip. * @param fn - The function to use to zip the tuples. * @param arr1 - The first tuple to zip. * @param arr2 - The second tuple to zip. * @returns The zipped tuple. * @example * ```ts * type T0 = Call, [1, 2, 3], [10, 2, 5]>; // [[1, 10], [2, 2], [3, 5]] * type T1 = Call>; // [[1, 10], [2, 2], [3, 5]] * type T3 = Call, [1, 2, 3], [10, 2, 5]>; // [11, 4, 8] * ``` */ export type ZipWith = PartialApply, [ arr0, arr1, arr2, arr3, arr4, arr5, arr6, arr7, arr8, arr9 ]>; /** * Group values in a tuple into an object, using a predicate * to compute the key of each group. * @param fn - function applied to all values in the tuple to get a key. * @param tuple - A list of element * @returns an object containing a list of element for each key. * @example * ```ts * interface IsNumber extends Fn { * return: this["arg0"] extends number ? true : false; * } * * type T0 = Call, [1, "str", 2]>; * // ^? { true: [1, 2], false: ["str"] } * type T2 = Call>, ["alice", "bob", "carl"]>; * // ^? { true: ["alice"], false: ["bob", "carl"] } * ``` */ export interface GroupBy extends Fn { return: GroupByImpl; } type GroupByImplRec = xs extends [ infer first, ...infer rest ] ? Call extends infer key extends PropertyKey ? GroupByImplRec & { [K in key]: [ ...(key extends keyof acc ? Extract : []), first ]; }> : never : acc; export type GroupByImpl = Prettify>; /** * Range takes a `start` and an `end` integer and produces * a tuple containing integer ranging from `start` to `end` * @param start - the start of the range (included) * @param end - the end of the range (included) * @returns a tuple of integers * @example * ```ts * type T0 = Call, 7>; // [3, 4, 5, 6, 7] * type T1 = Call, 5>; // [5, 6, 7, 8, 9, 10] * type T3 = Call, 5>; // [-2, 1, 0, 1, 2] * type T4 = Call, 5>; // [-5, -4, -3, -2] * ``` */ export type Range = PartialApply; interface RangeFn extends Fn { return: this["args"] extends [ infer start extends number, infer end extends number ] ? Call extends true ? Pipe, Numbers.Add<1>, Numbers.Abs ]> extends infer length extends number ? RangeImpl : never : never : never; } type RangeImpl = output["length"] extends length ? output : RangeImpl> ]>; /** * Returns the length of a tuple * @param tuple - any tuple * @returns a number * @example * ```ts * type T0 = Call; // 3 * type T1 = Call; 0 * type T2 = Call; 1 * ``` */ export type Length = PartialApply; interface LengthFn extends Fn { return: this["args"] extends [infer tuple extends readonly any[], ...any] ? tuple["length"] : never; } /** * Takes a tuple of numbers and returns the smallest one * @param tuple - a tuple of numbers * @returns a number * @example * ```ts * type T0 = Call; // 1 * type T1 = Call; // -3 * type T2 = Call; never * ``` */ export type Min = PartialApply; interface MinFn extends Fn { return: this["args"] extends [ infer tuple extends readonly (number | bigint)[], ...any ] ? MinImpl : never; } type MinImpl = xs extends [ infer first extends number | bigint, ...infer rest ] ? MinImpl> : min; /** * Takes a tuple of numbers and returns the smallest one * @param tuple - a tuple of numbers * @returns a number * @example * ```ts * type T0 = Call; // 3 * type T1 = Call; // -1 * type T2 = Call; never * ``` */ export type Max = PartialApply; interface MaxFn extends Fn { return: this["args"] extends [ infer tuple extends readonly (number | bigint)[], ...any ] ? MaxImpl : never; } type MaxImpl = xs extends [ infer first extends number | bigint, ...infer rest ] ? MaxImpl> : min; export {}; }