【问题标题】:Cannot invoke expressions whose type lacks a call signature无法调用类型缺少调用签名的表达式
【发布时间】:2016-10-11 03:22:53
【问题描述】:

在这个简化的示例中使用适配器时,我收到一个类型错误(参见方法getGloryOfAnimal 的最后一行)。我很困惑,因为据我所知,这些类型已经完全解释了。

interface ICheetah {
    pace: string;
}

interface ILion {
    mane: string;
}

let LionAdapter = {
    endpoint: 'lion',
    castRawData: (d: any) => d as ILion,
    getValue: (d: ILion) => d.mane
}

let CheetahAdapter = {
    endpoint: 'cheetah',
    castRawData: (d: any) => d as ICheetah,
    getValue: (d: ICheetah) => d.pace
}

type AnimalAdapter = typeof CheetahAdapter | typeof LionAdapter;

function getDataFromEndpoint(endpoint: string): any {
    // data comes back in a format from the server
    // synchronous here for simplicity
    if (endpoint === 'cheetah') {
        return {
            pace: 'lightning speed'
        };
    } else {
        return {
            mane: 'shiny mane'
        };
    }
}

function getGloryOfAnimal(adapter: AnimalAdapter): string {
    let data = adapter.castRawData(getDataFromEndpoint(adapter.endpoint));
    // type error below:
    // 'cannot invoke expression whose type lacks a call signature'
    return adapter.getValue(data); 
}

console.log(getGloryOfAnimal(LionAdapter));

我相信我可以为两个适配器编写一个接口,而不是创建一个联合类型(例如(T | U)),但在我的情况下,接口会非常大。

想法?我是否坚持为适配器创建一个巨大的通用接口?

【问题讨论】:

    标签: typescript typescript2.0


    【解决方案1】:

    这个错误的原因是adapter.getValue的类型是:

    ((d: ICheetah) => string) | ((d: ILion) => string)
    

    而且这种类型确实缺少调用签名。

    data的类型是:

    ICheetah | ILion
    

    如果adapter.getValue 的类型是:

    (d: ICheetah | ILion) => string
    

    我的问题是你为什么不使用类?那么实际的函数将是类型已知的类方法。


    编辑

    您可以通过以下方式解决此错误:

    let LionAdapter = {
        endpoint: 'lion',
        getValue: (d: any) => d.mane
    }
    
    let CheetahAdapter = {
        endpoint: 'cheetah',
        getValue: (d: any) => d.pace
    }
    
    function getGloryOfAnimal(adapter: AnimalAdapter): string {
        return adapter.getValue(getDataFromEndpoint(adapter.endpoint)); 
    }
    

    这也消除了对castRawData 的需要。
    如果您仍然需要类型安全,请将 d 替换为 (d as ICheetah)

    【讨论】:

    • 如果我制作这样的适配器,我也会遇到同样的问题:class CheetahAdapter { endpoint: 'cheetah'; castRawData (d: any) { return d as ICheetah} getValue (d: ICheetah) { return d.pace; } }我误解你的意思了吗?
    • 也许您是在建议它们应该继承自一个通用抽象类?在我的上下文中这很困难,因为有许多端点以各种方式重叠。我想在我知道这些适配器的一个子集满足必要条件的各种情况下使用这些适配器。
    • 我不能说我理解你想要做什么,所以我只能提供一个解决方法来帮助你,请查看我修改后的答案。如果您能解释更多,那么也许可以找到更好的解决方案
    猜你喜欢
    • 2017-09-01
    • 2017-12-19
    • 2021-02-06
    • 2017-07-14
    • 2017-03-17
    • 1970-01-01
    • 1970-01-01
    • 2020-02-07
    • 2017-02-03
    相关资源
    最近更新 更多