代码之家  ›  专栏  ›  技术社区  ›  Amit Wagner

无法调用其类型缺少调用签名的表达式…没有兼容的调用签名

  •  1
  • Amit Wagner  · 技术社区  · 6 年前

    我有个错误

    Cannot invoke an expression whose type lacks a call signature ... has no compatible call signatures.
    

    在我的一个方法上,我想不出怎么解决它。 我看过这个链接 cannot-invoke-an-expression-whose-type-lacks-a-call-signature

    类型声明:

    type ProcessMethods = "execute" | "execSpawn"
    
    interface IDeferedCmd {
        type: ProcessMethods,
        cmd: string,
        name: string,
        resolve: IResolveFn,
        reject: IRejectFn,
        args?: Array<string>,
        options?: object
    
    
    }

    static execute({cmd, name}: { cmd: string, name: string }): Promise<{
            stdout: string;
            stderr: string;
        }>
    
    static execSpawn({cmd, name, args , options }: { cmd: string, name: string, args: Array<string>, options: object }): Promise<NodeJS.ReadableStream>

    还有第三个方法,在这个方法中,错误是从尝试动态调用它们时抛出的

    if (typeof firstDeferedCmd == "object" && ( firstDeferedCmd.type === "execute" || firstDeferedCmd.type === "execSpawn" )) {
                    ProcessPoolExecutor[firstDeferedCmd.type](firstDeferedCmd); // this line throw the error
    }

    以及它本身的错误

    ProcessPoolExecutorfirstDeferedCmd.type; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    1 回复  |  直到 6 年前
        1
  •  1
  •   Titian Cernicova-Dragomir    6 年前

    问题是这两个函数有不同的签名,因此索引操作的结果将是两个签名的联合,根据定义,这两个签名是不可调用的。

    Function 方法 call apply 可访问(因为它们对联合体中的两个签名都是通用的)来调用函数,但缺点是会丢失所有类型安全性:

    if (typeof firstDeferedCmd == "object" && ( firstDeferedCmd.type === "execute" || firstDeferedCmd.type === "execSpawn" )) {
        ProcessPoolExecutor[firstDeferedCmd.type].call(ProcessPoolExecutor, firstDeferedCmd);
    }
    

    您可以始终使用断言使联合可调用,但这样做并不安全 :

    if (typeof firstDeferedCmd == "object" && ( firstDeferedCmd.type === "execute" || firstDeferedCmd.type === "execSpawn" )) {
        (ProcessPoolExecutor[firstDeferedCmd.type] as (cmd: IDeferedCmd) => Promise<{stdout: string;stderr: string;}> | Promise<NodeJS.ReadableStream>)(firstDeferedCmd);
    }
    

    您还可以使用两个检查来指定两个不同的签名,这实际上暴露了当前设计的一个问题:

    function fn(firstDeferedCmd : IDeferedCmd){
        if (typeof firstDeferedCmd == "object") {
            if(firstDeferedCmd.type === "execute") {
                return ProcessPoolExecutor[firstDeferedCmd.type](firstDeferedCmd);
            }
            if(firstDeferedCmd.type === "execSpawn") {
                if(firstDeferedCmd.args){
                    return ProcessPoolExecutor[firstDeferedCmd.type](firstDeferedCmd);  // error since there is no requirement if execSpawn is specified to also specify args
                }
            }
        }
    }
    

    我们可以通过改变 IDeferedCmd

    type IDeferedCmd = {
        type: "execute",
        cmd: string,
        name: string,
    } | {
        type: "execSpawn",
        cmd: string,
        name: string,
        resolve: IResolveFn,
        reject: IRejectFn,
        args: Array<string>,
        options: object
    
    
    }
    function fn(firstDeferedCmd : IDeferedCmd){
        if (typeof firstDeferedCmd == "object") {
            if(firstDeferedCmd.type === "execute") {
                return ProcessPoolExecutor[firstDeferedCmd.type](firstDeferedCmd);
            }
            if(firstDeferedCmd.type === "execSpawn") {
                if(firstDeferedCmd.args){
                    return ProcessPoolExecutor[firstDeferedCmd.type](firstDeferedCmd);  // ok now
                }
            }
        }
    }