UNPKG

remeda

Version:

A utility library for JavaScript and Typescript.

67 lines (66 loc) 4.68 kB
import { IntRangeInclusive } from "./IntRangeInclusive-Dd730-dm.js"; import { IterableContainer } from "./IterableContainer-B2PfkIAC.js"; import { NTuple } from "./NTuple-sy5afYiG.js"; import { NonEmptyArray } from "./NonEmptyArray-Dsqj_iOR.js"; import { PartialArray } from "./PartialArray-CGJOFu0O.js"; import { TupleParts } from "./TupleParts-Dc0oO91w.js"; import { IfNever, IntRange, IsNumericLiteral, LessThan, Subtract, ValueOf } from "type-fest"; //#region src/chunk.d.ts type MAX_LITERAL_SIZE = 350; type Chunk<T extends IterableContainer, N extends number> = T extends readonly [] ? [] : IsNumericLiteral<N> extends true ? LessThan<N, 1> extends true ? never : LessThan<N, MAX_LITERAL_SIZE> extends true ? [...LiteralChunk<T, N>] : GenericChunk<T> : GenericChunk<T>; type LiteralChunk<T extends IterableContainer, N extends number> = ChunkRestElement<ChunkFixedTuple<TuplePrefix<T>, N>, TupleParts<T>["item"], TupleParts<T>["suffix"], N> | ([...TuplePrefix<T>, ...TupleParts<T>["suffix"]] extends readonly [] ? [] : never); /** * This type **only** works if the input array `T` is a fixed tuple. For these * inputs the chunked output could be computed as literal finite tuples too. */ type ChunkFixedTuple<T, N extends number, Result = []> = T extends readonly [infer Head, ...infer Rest] ? ChunkFixedTuple<Rest, N, Result extends [...infer Previous extends Array<Array<unknown>>, infer Current extends Array<unknown>] ? Current["length"] extends N ? [...Previous, Current, [Head]] : [...Previous, [...Current, Head]] : [[Head]]> : Result; /** * Here lies the main complexity of building the chunk type. It takes the prefix * chunks, the rest param item type, and the suffix (not chunked!) and it * creates all possible combinations of adding items to the prefix and suffix * for all possible scenarios for how many items the rest param "represents". */ type ChunkRestElement<PrefixChunks, Item, Suffix extends Array<unknown>, N extends number> = IfNever<Item, PrefixChunks, PrefixChunks extends [...infer PrefixFullChunks extends Array<Array<unknown>>, infer LastPrefixChunk extends Array<unknown>] ? ValueOf<{ [Padding in IntRangeInclusive<0, Subtract<N, LastPrefixChunk["length"]>>]: [...PrefixFullChunks, ...ChunkFixedTuple<[...LastPrefixChunk, ...NTuple<Item, Padding>, ...Suffix], N>] }> | [...PrefixFullChunks, [...LastPrefixChunk, ...NTuple<Item, Subtract<N, LastPrefixChunk["length"]>>], ...Array<NTuple<Item, N>>, ...SuffixChunk<Suffix, Item, N>] : [...Array<NTuple<Item, N>>, ...SuffixChunk<Suffix, Item, N>]>; /** * This type assumes it takes a finite tuple that represents the suffix of our * input array. It builds all possible combinations of adding items to the * **head** of the suffix in order to pad the suffix until the last chunk is * full. */ type SuffixChunk<T extends Array<unknown>, Item, N extends number> = T extends readonly [] ? [ValueOf<{ [K in IntRangeInclusive<1, N>]: NTuple<Item, K> }>] : ValueOf<{ [Padding in IntRange<0, N>]: ChunkFixedTuple<[...NTuple<Item, Padding>, ...T], N> }>; /** * This is the legacy type used when we don't know what N is. We can only adjust * our output based on if we know for sure that the array is empty or not. */ type GenericChunk<T extends IterableContainer> = T extends readonly [...Array<unknown>, unknown] | readonly [unknown, ...Array<unknown>] ? NonEmptyArray<NonEmptyArray<T[number]>> : Array<NonEmptyArray<T[number]>>; type TuplePrefix<T extends IterableContainer> = [...TupleParts<T>["required"], ...PartialArray<TupleParts<T>["optional"]>]; /** * Split an array into groups the length of `size`. If `array` can't be split evenly, the final chunk will be the remaining elements. * * @param array - The array. * @param size - The length of the chunk. * @signature * R.chunk(array, size) * @example * R.chunk(['a', 'b', 'c', 'd'], 2) // => [['a', 'b'], ['c', 'd']] * R.chunk(['a', 'b', 'c', 'd'], 3) // => [['a', 'b', 'c'], ['d']] * @dataFirst * @category Array */ declare function chunk<T extends IterableContainer, N extends number>(array: T, size: N): Chunk<T, N>; /** * Split an array into groups the length of `size`. If `array` can't be split evenly, the final chunk will be the remaining elements. * * @param size - The length of the chunk. * @signature * R.chunk(size)(array) * @example * R.chunk(2)(['a', 'b', 'c', 'd']) // => [['a', 'b'], ['c', 'd']] * R.chunk(3)(['a', 'b', 'c', 'd']) // => [['a', 'b', 'c'], ['d']] * @dataLast * @category Array */ declare function chunk<N extends number>(size: N): <T extends IterableContainer>(array: T) => Chunk<T, N>; //#endregion export { chunk }; //# sourceMappingURL=chunk-BdR9P8p3.d.ts.map