来自其他两个功能的合成构建功能

时间:2019-02-04 01:33:22

标签: typescript

我对TypeScript重载不满意,事情会变得非常复杂。我正在寻找一种方法来从两个单独的函数组成“重载”。是否可以通过以下一个函数合并这两个函数,而该函数具有接受传递的相同参数的能力?所有类型都按顺序排列。

function fromFileQuery (a: FileQuery): FileQuery {
    if (!a.path) throw new Error('missing path');
    return {
        path: a.path,
        encoding: a.encoding || null,
        flag: a.flag || FileSystemFlags.R
    };
}

function fromFilePathOptions (...args: FilePathOptions): FileQuery {
    const [path, fileQuery] = args;
    return fromFileQuery({...fileQuery, path});
}

const getFileQuery = make([fromFileQuery, fromFilePathOptions])

getFileQuery支持FileQueryFilePathOptions的地方。

这是我走的远了:

type ArgumentTypes<F extends Function> = F extends (...args: infer A) => any ? A : never;

function make(fns: any[]): Function {
    type input = ArgumentTypes<typeof fns[0]>;
    type output = ReturnType<typeof fns[0]>;
    return (...arg: input): output => {

    }
}

const x = make([fromFileQuery, fromFilePathOptions]);

1 个答案:

答案 0 :(得分:1)

在这种情况下获取锻炼的类型并不是特别困难。

我们首先需要捕获所有函数类型。最好使用tuples in rest parameters完成此操作。然后,我们需要获取函数的所有参数类型和所有返回类型。从3.1开始,我们可以使用mapped tuples

type AllParameters<T> = { [P in keyof T]: T[P] extends (...a: any[])=> any ? Parameters<T[P]> : never }
type AllReturnTypes<T> = { [P in keyof T]: T[P] extends (...a: any[])=> any ? ReturnType<T[P]> : never }
function make<T extends Array<(...a: any[])=> any>>(...fns: T){
    return (...arg: AllParameters<T>[number]): AllReturnTypes<T>[number] => {
        for(var fn of fns){
            if(fn.length === arg.length) {
                return fn(...arg);
            }
        }
        throw new Error("Not supported")
    }
}

function fromFileQuery (a: FileQuery): FileQuery {
    if (!a.path) throw new Error('missing path');
    return {
        path: a.path,
        encoding: a.encoding || null,
        flag: a.flag || FileSystemFlags.R
    };
}

function fromFilePathOptions (path: string, fileQuery: FileQuery): FileQuery {
    return fromFileQuery({...fileQuery, path});
}

const getFileQuery = make(fromFileQuery, fromFilePathOptions)

const x = make(fromFileQuery, fromFilePathOptions);

x({
    flag: "",
    encoding: "",
    path: ""
});

x("", {
    flag: "",
    encoding: ""
})

更困难的部分是确定要调用的函数。在上面的示例中,我选择使用fn.length === arg.length,因此选择要调用的函数。显然,这并不是在所有情况下的最佳解决方案。我们可能还会考虑添加一个额外的函数来决定要调用哪个函数。

希望这会有所帮助,让我知道我是否还能提供其他帮助,感谢您的反馈:)