Skip to content

Truly variadic pipe type #233

@AZMCode

Description

@AZMCode

Has anyone here considered using recursive/conditional/inferred types to allow typescript to statically type the pipe function in a truly variadic way?

Here's an example of what's possible, applied to simple function composition, if only requiring some casts to achieve, but in exchange allowing for infinitely large truly variadic pipe:

type PipeReturn<Rest extends ((x: any) => any)[]> =
    Rest extends [infer F1 extends (x: any) => any,infer F2 extends (x: any) => any, ...infer RestTail extends ((x: any) => any)[]] ?
        ReturnType<F1> extends Parameters<F2>[0] ?
            PipeReturn<[(x: Parameters<F1>[0]) => ReturnType<F2>,...RestTail]> :
            never :
        Rest extends [(x: infer A) => infer B] ?
            (x: A) => B :
            Rest extends [] ?
                <T>(x: T) => T :
                ((x: any) => any)
    ;


function pipe<F extends ((x: any) => any)[]>(...fs: F): PipeReturn<F> {
    if(fs.length === 0) return (<T>(x: T) => x) as PipeReturn<F>;
    if(fs.length === 1) return fs[0] as PipeReturn<F>;
    const [f,...rest] = fs;
    return ((x: any) => f(pipe(...rest))) as PipeReturn<F>;
} 

This typechecks in typescript 5.4.5

To clarify my point, despite using any everywhere in the type definition, this makes the pipe function be truly variadic, using type recursion. Ensuring type safety between the return type of the previous function and parameter of the nextfunction, using conditional and inferred types. The case where the length of the function tuple is not known is covered by a default (x: any) => any in the last branch, but this could be changed to anything.

The only real downside I can see to this is probably my poorly-performing pipe function implementation, which can be changed to the existing definition if needed, and lacking support for older typescript versions that don't have these features.

I'm sure a similar approach could be used for Operators, as defined in this library.
I can start work on it if the author deems it useful enough.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions