32427-hard-unbox

Back

type Unbox<T, Depth extends number = 0, Count extends '🍌'[] = Depth extends 0 ? never : []> =
  Depth extends Count['length']
    ? T
  : T extends Box<infer I>
    ? Unbox<I, Depth, [...Count, '🍌']>
  : T;
type Box<I> = (() => I) | I[] | Promise<I>;

Playground

Solution by teamchong #32987

type UnboxRec<T, D, C extends 1[]> = C['length'] extends D
  ? T
  : T extends (readonly (infer I)[] | PromiseLike<infer I> | (() => infer I))
    ? UnboxRec<I, D, [...C, 1]>
    : T;

type Unbox<T, D = 0> = UnboxRec<T, Exclude<D, 0>, []>;

Solution by alexandroppolus #32965

type Unbox<T, L extends number = 0, C extends number[] = []> =
  C['length'] extends L
    ? L extends 0
      ? Unbox<T, L, [0]>
      : T
    : T extends ((...args: any[]) => infer R) | (infer R)[] | Promise<infer R>
      ? Unbox<R, L, [...C, 0]>
      : T

Solution by XkSuperCool #32808

type SimpleUnbox<T> =
    T extends (infer V)[] ? V :
    T extends () => infer V ? V :
    T extends Promise<infer V> ? V :
    T;

type DeepUnbox<T, R = SimpleUnbox<T>> = T extends R ? T : DeepUnbox<R>;

type FakeArray<N extends number, T extends any[] = []> = T['length'] extends N ? T : FakeArray<N, [...T, any]>;

type Decrement<N extends number, A = FakeArray<N>> = A extends [any, ...infer T extends any[]] ? T['length'] : -1;

type Unbox<T, C extends number = -1> =
  C extends -1 | 0 ? DeepUnbox<T> :
    C extends 1 ? SimpleUnbox<T> :
     Unbox<SimpleUnbox<T>, Decrement<C>>;

Solution by alexbidenko #32566

type Primitive = number | string | boolean

type Unbox<T, N extends number = 0, Cur extends 1[] = [1] >
    = Cur['length'] extends N
      ? T extends () => infer R1 ? R1
        : T extends (infer R2)[] ? R2
          : T extends Promise<infer R3> ? R3
            : T
      : T extends () => infer R1 ? R1 extends Primitive ? R1 : Unbox<R1, N, [...Cur, 1]>
        : T extends (infer R2)[] ? R2 extends Primitive ? R2 : Unbox<R2, N, [...Cur, 1]>
          : T extends Promise<infer R3> ? R3 extends Primitive ? R3 : Unbox<R3, N, [...Cur, 1]>
            : T

Solution by Heonys #32511

type Unbox<T, Depth = 0, Count extends any[] = [1]> = T extends ((...args: any[]) => infer R) | (infer R)[] | Promise<infer R>
  ? Count['length'] extends Depth ? R : Unbox<R, Depth, [...Count, 1]>
  : T

Solution by Sun79 #32469

type Unbox<T, Deep extends number = 0, _DeepRecorder extends 1[] = []> =
  Deep extends 0 ? Unbox<T, -1> : //To Infinity
  _DeepRecorder[`length`] extends Deep ? T :
  T extends Promise<infer R> ? Unbox<R, Deep, [..._DeepRecorder, 1]> :
  T extends () => infer R ? Unbox<R, Deep, [..._DeepRecorder, 1]> :
  T extends (infer R)[] ? Unbox<R, Deep, [..._DeepRecorder, 1]> :
  T;

Solution by E-uler #32458