Search code examples
typescripttypescript-generics

How to use a recursive variadic tuple as a function parameter type


I have a contrived recursive tuple definition:

type TupleRecursion<T> =
  T extends [infer HEAD, ...infer TAIL]
    ? [HEAD, ...TupleRecursion<TAIL>]
    : [];

and then I try to constrain my function's parameters using this type. I would expect such a function to allow any tuple:

function foo<T>(tuple: TupleRecursion<T>) {}

However, when I call the function with a tuple with two elements:

test(["test", "hi"]);

I get the error "Source has 2 element(s) but target allows only 0".

Why is this happening? How can I get TS to accept a tuple of any length and correctly infer its type?

If it matters why I'm doing this, it's because I really want TupleRecursion<T> to constrain the tuple further (specifically, enforce that each element in the tuple satisfies a mapping from the previous element).


Solution

  • type ConvertRecursiveTuple<T> = T extends [infer One, ...infer Rest] 
     ? Rest extends []
       ? [One]
       : [One, ...ConvertRecursiveTuple<Rest>]
     : [];
    
    function foo<T extends any[]>(tuple: T & ConvertRecursiveTuple<T>) {
      return tuple;
    }
      
    const a = foo(["hello", 123, false]);