Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

array and conditional recursive types for a rest parameter in typescript 4.1

Tags:

typescript

I was wanting to use conditional types for a rest parameter but I was surprised when I did a test first

Here is a playground and here is the code:

type ExtractParts<P extends any[]> =
    P extends [infer H, ...infer U]
      ? ['yes way']
      : ['no way']


interface A {
  description: string;
  action: () => {
      say: string;
      it: string;
  };
}

type Q = ExtractParts<[1,2,3]> // ['yes]
type P = ExtractParts<A[]>; // ['no way']

type R = ExtractParts<[{    // ['yes way']
  description: string;
  action: () => {
      say: string;
      it: string;
  };
}]>;

I was surprised by this behaviour

type P = ExtractParts<A[]>; // ['no way']

But this works as I think because it is a strict tuple

type R = ExtractParts<[{    // ['yes way']
  description: string;
  action: () => {
      say: string;
      it: string;
  };
}]>;

I wanted to use this technique with a rest parameter

type ExtractParts<P extends any[]> =
    P extends [infer H, ...infer U]
      ? ['yes way']
      : ['no way']


function parts<P extends any[]>(...parts: ExtractParts<P>){}

const b = parts(1,2,3);

But P extends [infer H, ...infer U] returns false

Can I use conditional types like this to infer the head and tail for rest parameters?

like image 573
dagda1 Avatar asked Oct 26 '22 16:10

dagda1


1 Answers

The problem arises from the fact that an array can have 0 elements, while the tuple [H, ...T] must have at least one element. You can define a tuple with an optional first element, [H?, ...T] and that will be a base type for an array.

So in a conditional type you would use [(infer H)?, ...infer U]

type ExtractParts<P extends any[]> =
    P extends [(infer H)?, ...infer U]
      ? ['yes way']
      : ['no way']


interface A {
  description: string;
  action: () => {
      say: string;
      it: string;
  };
}


type Q = ExtractParts<[1,2,3]> // ['yes way']
type P = ExtractParts<A[]>; // ['yes way']

Playground Link

like image 59
Titian Cernicova-Dragomir Avatar answered Nov 22 '22 19:11

Titian Cernicova-Dragomir