ghaiklor / type-challenges-solutions

Solutions for the collection of TypeScript type challenges with explanations
https://ghaiklor.github.io/type-challenges-solutions/
Creative Commons Attribution 4.0 International
470 stars 56 forks source link

type-challenges-solutions/en/medium-chunk #193

Open utterances-bot opened 2 years ago

utterances-bot commented 2 years ago

Chunk

This project is aimed at helping you better understand how the type system works, writing your own utilities, or just having fun with the challenges.

https://ghaiklor.github.io/type-challenges-solutions/en/medium-chunk.html

DaniGuardiola commented 2 years ago

Here's my naïve initial attempt (before reading this solution):

type DecrementMap = {
  5: 4;
  4: 3;
  3: 2;
  2: 1;
  1: 0;
};
type Decrement<N extends number> = N extends keyof DecrementMap
  ? DecrementMap[N]
  : never;

type Chunk<
  Arr extends readonly unknown[],
  N extends number,
  C extends number = N,
  Acc extends readonly unknown[] = [],
  CurrentAcc extends readonly unknown[] = []
> = Arr extends [infer H, ...infer T]
  ? C extends 0
    ? // counter is done
      Chunk<Arr, N, N, [...Acc, CurrentAcc], []> // reset counter and push current into acc
    : // counter was decreased
      Chunk<T, N, Decrement<C>, Acc, [...CurrentAcc, H]> // decrement counter and push head into current
  : CurrentAcc extends []
  ? Acc
  : [...Acc, CurrentAcc]; // if not empty, add current
zhaoyao91 commented 1 year ago

Wow, what an elegant result!

Share my solution which is accidentally tail-recursive for comparison and disscusion.

issue

type Flatten<T extends any[][]> = T extends [infer First extends any[], ... infer Rest extends any[][]] ? [...First, ...Flatten<Rest>] : []

type Chunk<T extends any[], N extends number, R extends any[][] = [[]]> = 
  T extends []
    ? []
    : T['length'] extends Flatten<R>['length']
      ? R
      : R extends [...infer Rest extends any[][], infer Last extends any[]]
        ? Last['length'] extends N
          ? Chunk<T, N, [...Rest, Last, []]>
          : Chunk<T, N, [...Rest, [...Last, T[Flatten<R>['length']]]]>
        : never
mlyundin commented 1 year ago

Slightly readable...

type Chunk<T, N, A extends unknown[] = [], L = A["length"]> = T extends [infer F, ...infer Other]
  ? (L extends N ? [A, ...Chunk<T, N>] : Chunk<Other, N, [...A, F]>)
  : (L extends 0 ? [] : [A]);
albert-luta commented 1 year ago

My first take on a tail recursive approach

type Chunk<
  T extends unknown[],
  N extends number,
  Acc extends unknown[][] = [[]]
> = [T, Acc] extends [
  [infer Head, ...infer Tail],
  [...infer FirstPart extends unknown[][], infer Last extends unknown[]]
]
  ? Chunk<
      Tail,
      N,
      Last["length"] extends N
        ? [...FirstPart, Last, [Head]]
        : [...FirstPart, [...Last, Head]]
    >
  : Acc extends [[]]
  ? []
  : Acc;