首页 文章

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

提问于
浏览
1

我收到一个错误

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

还有2个,但仍然没有想到这一点

类型声明:

type ProcessMethods = "execute" | "execSpawn"

interface IDeferedCmd {
    type: ProcessMethods,
    cmd: string,
    name: string,
    resolve: IResolveFn,
    reject: IRejectFn,
    args?: Array<string>,
    options?: object


}

在我的 class ,我有2个静态方法,看起来像这样

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
}

而它自己的错误

无法调用类型缺少调用签名的表达式 . 输入'(({cmd,name}:{cmd:string; name:string;})=> Promise <{}>)| (({cmd,name,args,options} ...'没有兼容的调用签名.ProcessPoolExecutorfirstDeferedCmd.type; ~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1 回答

  • 1

    问题是这两个函数具有不同的签名,因此索引操作的结果将是两个签名的并集,根据定义它们是不可调用的 .

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

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

    您总是可以使用断言来使联合可调用,但这并不比 call 更安全:

    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
                }
            }
        }
    }
    

相关问题