/* eslint-disable @typescript-eslint/no-unsafe-function-type, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return */ type ValidFlow< Fns > = Fns extends [] ? [] : Fns extends [ ( i: infer I ) => infer R ] ? [ ( i: I ) => R ] : Fns extends [ ( i: infer I1 ) => infer O1, ...infer Rest1 ] ? Rest1 extends [ ( i: infer I2 ) => any, ...infer Rest2 ] ? [ O1 ] extends [ I2 ] ? [ ( i: I1 ) => O1, ...ValidFlow< Rest1 > ] : [ ( i: I1 ) => O1, ( i: O1 ) => unknown, ...ValidFlow< Rest2 > ] : [ never ] : [ never ]; type Input< Fns extends Function[] > = Fns extends [ ( i: infer I ) => any, ...Function[], ] ? I : never; type Output< Fns extends Function[] > = Fns extends [ ( i: any ) => infer R, ...infer Rest, ] ? Rest extends [] ? R : Rest extends Function[] ? Output< Rest > : never : never; export function flow< Fns extends Function[] >( ...fns: Fns extends ValidFlow< Fns > ? Fns : ValidFlow< Fns > ): ( input: Input< Fns > ) => Output< Fns > { return ( input: Input< Fns > ) => ( fns as Array< ( i: any ) => any > ).reduce( ( r, f ) => f( r ), input as any ) as Output< Fns >; }