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

Posted

技术标签:

【中文标题】无法调用其类型缺少调用签名的表达式...没有兼容的调用签名【英文标题】:Cannot invoke an expression whose type lacks a call signature ... has no compatible call signatures 【发布时间】:2019-01-26 06:58:47 【问题描述】:

我得到一个错误

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

及其自身的错误

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

【问题讨论】:

【参考方案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
            
        
    

【讨论】:

以上是关于无法调用其类型缺少调用签名的表达式...没有兼容的调用签名的主要内容,如果未能解决你的问题,请参考以下文章

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

无法调用其类型缺少调用签名的表达式

类型数组的打字稿错误:- 无法调用其类型缺少调用签名的表达式

错误 TS2349:无法调用其类型缺少调用签名的表达式

使用 node-fetch 时无法调用其类型缺少调用签名的表达式

Typescript中的“无法调用类型缺少调用签名的表达式”?