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

新手上路,请多包涵

我有苹果和梨 - 都有 isDecayed 属性:

 interface Apple {
    color: string;
    isDecayed: boolean;
}

interface Pear {
    weight: number;
    isDecayed: boolean;
}

两种类型都可以在我的水果篮中(多次):

 interface FruitBasket {
   apples: Apple[];
   pears: Pear[];
}

现在假设我的篮子是空的:

 const fruitBasket: FruitBasket = { apples: [], pears: [] };

现在我们从篮子里随机取出一种:

 const key: keyof FruitBasket = Math.random() > 0.5 ? 'apples': 'pears';
const fruits = fruitBasket[key];

当然没有人喜欢腐烂的水果,所以我们只挑选新鲜的:

 const freshFruits = fruits.filter((fruit) => !fruit.isDecayed);

不幸的是 Typescript 告诉我:

无法调用其类型缺少调用签名的表达式。输入 ‘((callbackfn: (value: Apple, index: number, array: Apple[]) => any, thisArg?: any) => Apple[]) | …’ 没有兼容的调用签名。

这里有什么问题 - 仅仅是 Typescript 不喜欢新鲜水果还是这是一个 Typescript 错误?

你可以在官方的 Typescript Repl%20%3D%3E%20!fruit.isDecayed)%3B) 中自己尝试一下。

原文由 user6551614 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 769
2 个回答

TypeScript 支持结构类型(也称为鸭子类型),这意味着 类型在共享相同成员时是兼容的。您的问题是 ApplePear 不共享所有成员,这意味着它们不兼容。然而,它们与只有 isDecayed: boolean 成员的另一种类型兼容。由于结构类型,您不需要从这样的接口继承 ApplePear

分配这种兼容类型有不同的方法:

在变量声明期间分配类型

此语句隐式键入为 Apple[] | Pear[]

 const fruits = fruitBasket[key];

您可以简单地在变量声明中显式使用兼容类型:

 const fruits: { isDecayed: boolean }[] = fruitBasket[key];

为了增加可重用性,您还可以先定义类型,然后在声明中使用它(注意 ApplePear 接口不需要更改):

 type Fruit = { isDecayed: boolean };
const fruits: Fruit[] = fruitBasket[key];

转换为操作的兼容类型

给定解决方案的问题在于它改变了 fruits 变量的类型。这可能不是你想要的。为避免这种情况,您可以在操作之前将数组缩小为兼容类型,然后将类型设置回与 fruits 相同的类型:

 const fruits: fruitBasket[key];
const freshFruits = (fruits as { isDecayed: boolean }[]).filter(fruit => !fruit.isDecayed) as typeof fruits;

或者使用可重复使用的 Fruit 类型:

 type Fruit = { isDecayed: boolean };
const fruits: fruitBasket[key];
const freshFruits = (fruits as Fruit[]).filter(fruit => !fruit.isDecayed) as typeof fruits;

此解决方案的优点是 fruitsfreshFruits 都属于 Apple[] | Pear[] 类型。

原文由 Sefe 发布,翻译遵循 CC BY-SA 3.0 许可协议

正如@peter 在评论中最初链接的 github问题 中提到的那样:

 const freshFruits = (fruits as (Apple | Pear)[]).filter((fruit: (Apple | Pear)) => !fruit.isDecayed);

原文由 shusson 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题