Search code examples
typescripttype-inferenceextendsconditional-types

In TypeScript why does [1, 2] extend [...unknown[], 0, ...unknown[]]?


I'm trying to understand how infer in TypeScript conditional types work. One thing I've noticed about infer types in TypeScript is that they are defined to allow a rest element following another rest element. For example:

type A<T> = T extends [...infer X, 0, ...infer Y] ? [X, Y] : never;
type B = A<[1, 2]>; // B = [unknown[], unknown[]]

Interestingly, not only does TypeScript say this code is valid; the condition also succeeds, giving us X = unknown[] and Y = unknown[]. However, when we substitute in these inferred types, TypeScript gives us an error:

type C<T> = T extends [...unknown[], 0, ...unknown[]] ? true : false;
// Error: A rest element cannot follow another rest element. (1265)

Why does TypeScript require you to use infer when using multiple rest elements, and why does it say that the type [1, 2] contains the element 0?


Solution

  • Even though they don't throw an error in an extends clause, multiple rest types are not really supported. It is a known issue, currently considered a design limitation and unlikely to be fixed (emphasis mine):

    This is unfortunately a design limitation as we have a very narrow heuristic that provides rudimentary support for inferring to multiple rest types in a tuple. It's not clear at this time whether this is something we want to extend. While a useful minimal repro, the example shown in the issue description doesn't illustrate a need that would be sufficient motivation to reevaluate this limitation. It would be helpful to understand the specific needs this issue is trying to address.