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

标签 javascript typescript types

我得到一个错误

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


}

在我的课上我有 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
}

错误本身

Cannot invoke an expression whose type lacks a call signature. Type '(({ cmd, name }: { cmd: string; name: string; }) => Promise<{}>) | (({ cmd, name, args, options }...' has no compatible call signatures. ProcessPoolExecutorfirstDeferedCmd.type; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

最佳答案

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

您可以使用可访问的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
            }
        }
    }
}

关于javascript - 无法调用类型缺少调用签名的表达式...没有兼容的调用签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51925788/

相关文章:

TypeScript:是否可以定义一个创建函数实例的类?

javascript - StrictNullChecks 与通过语法的联合类型

typescript - 为什么 Function 扩展了 TypeScript 中的 Record?

TypeScript:将接口(interface)转换为类

javascript - 无法使用 Array.from 将 FileList 转换为 Array 并在 typescript 中传播语法

python - Python 3.X 中同名的类型和函数?

javascript - 检查 jQuery 中的值是否存在于 JSON 中

javascript - 改变质量的 webRTC

javascript - 覆盖背景 :url with background-color in CSS

javascript - 启用换行后如何在 Ace Editor 中禁用后续行的缩进