I'm trying to code a variadic pipe
function which composes an arbitrary number of one-argument pure functions.
This typing should check that the return type of one function is the argument type of the next and so on.
I would expect this to work in TypeScript 3.7 which introduces recursive types but somehow it doesn't work and gives the error:
TS2589: type instantiation is excessively deep and possibly infinite
Here's my code:
type Tail<T extends any[]> = ((...t: T) => void) extends ((x: any, ...u: infer U) => void) ? U : never;
type Pipe<FNS extends unknown[]> = FNS extends [(a: infer A) => infer B, (b: infer B) => infer C] ? C :
FNS extends [(a: infer A) => infer B, (b: infer B) => infer C, Pipe<[...Tail<FNS>[]]>] ? C : never;
The FNS
type represents the array of pure functions and the Tail
type should make sure that only the tail of this array is returned, but still the compiler marks this as an infinite loop.
Usage example:
const numToString = (n: number): string => n.toString();
const toUpper = (s: string): string => s.toUpperCase();
// this works, Foo evaluates to string
type Foo = Pipe<[typeof numToString, typeof toUpper]>;
// this doesn't work, Foo is not evaluated
type Foo = Pipe<[typeof numToString, typeof toUpper, typeof toUpper]>;
The error is on this part:
Pipe<[...Tail<FNS>[]]>
Why is this infinite? What am I missing?