是否可以输入 "spreadCall" 方法?有条件类型和推断的谜题

is it possible to type the "spreadCall" method? a puzzle with conditional type and infer

我在工作中遇到一个问题,我可以用这个例子来总结:是否可以完全键入以下函数?


    function spreadCall(f1, f2) {
        const args = f1();
        f2(...args);
    }

所以我们需要 f2 接受与 f1 的结果完全相同数量的参数(即元组),类型顺序相同。我想不出办法 - 我能想到的部分解决方案是枚举几个参数,即


    type Output<F> = 
         F extends ()=>[infer A0] ? (a0:A0)=>void :
         F extends ()=>[infer A0, infer A1] ? (a0:A0, a1:A1)=>void :
         F extends ()=>[infer A0, infer A1, infer A2] ? (a0:A0, a1:A1, a2:A2)=>void :
         never;
    // enumerate as many number of arguments as desired ^^

    function spreadCall<InputF>(f1:InputF, f2:Output<InputF>) {
        // ...
    }

有没有办法处理任意数量的参数?

我认为你可以使用 generic rest parameter type 来做你想做的事情:

function spreadCall<A extends any[]>(f1: () => A, f2: (...args: A) => any) {
    const args = f1();
    f2(...args);
}

f1 的 return 必须是与 f2 函数的参数类型匹配的 tuple:

declare function input(): [number, string]
declare function output(a: number, b: string): void;

spreadCall(input, output);