我有苹果和梨 - 都有 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 许可协议
TypeScript 支持结构类型(也称为鸭子类型),这意味着 类型在共享相同成员时是兼容的。您的问题是
Apple
和Pear
不共享所有成员,这意味着它们不兼容。然而,它们与只有isDecayed: boolean
成员的另一种类型兼容。由于结构类型,您不需要从这样的接口继承Apple
和Pear
。分配这种兼容类型有不同的方法:
在变量声明期间分配类型
此语句隐式键入为
Apple[] | Pear[]
:您可以简单地在变量声明中显式使用兼容类型:
为了增加可重用性,您还可以先定义类型,然后在声明中使用它(注意
Apple
和Pear
接口不需要更改):转换为操作的兼容类型
给定解决方案的问题在于它改变了
fruits
变量的类型。这可能不是你想要的。为避免这种情况,您可以在操作之前将数组缩小为兼容类型,然后将类型设置回与fruits
相同的类型:或者使用可重复使用的
Fruit
类型:此解决方案的优点是
fruits
和freshFruits
都属于Apple[] | Pear[]
类型。