我有苹果和梨-它们都有一个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 bug?
您可以在官方Typescript Repl中亲自体验。
发布于 2017-02-27 21:33:43
TypeScript支持结构化类型(也称为鸭子类型),这意味着types are compatible when they share the same members。您的问题是Apple
和Pear
不共享所有成员,这意味着它们不兼容。但是,它们与只有isDecayed: boolean
成员的另一种类型兼容。由于结构类型,您不需要从这样的接口继承Apple
和Pear
。
有不同的方法可以指定这样的兼容类型:
变量声明期间的赋值类型
此语句隐式类型化为Apple[] | Pear[]
const fruits = fruitBasket[key];
您只需在变量声明中显式使用兼容类型:
const fruits: { isDecayed: boolean }[] = fruitBasket[key];
为了增加可重用性,您还可以先定义类型,然后在声明中使用它(请注意,不需要更改Apple
和Pear
接口):
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;
此解决方案的优点是,fruits
和freshFruits
都将是Apple[] | Pear[]
类型。
发布于 2017-02-24 06:50:28
正如在评论中@peter最初链接的github issue中所提到的:
const freshFruits = (fruits as (Apple | Pear)[]).filter((fruit: (Apple | Pear)) => !fruit.isDecayed);
发布于 2017-02-24 06:35:51
也许可以创建一个提供isDecayed的共享Fruit
接口。fruits
现在的类型是Fruit[]
,因此该类型可以是显式的。如下所示:
interface Fruit {
isDecayed: boolean;
}
interface Apple extends Fruit {
color: string;
}
interface Pear extends Fruit {
weight: number;
}
interface FruitBasket {
apples: Apple[];
pears: Pear[];
}
const fruitBasket: FruitBasket = { apples: [], pears: [] };
const key: keyof FruitBasket = Math.random() > 0.5 ? 'apples': 'pears';
const fruits: Fruit[] = fruitBasket[key];
const freshFruits = fruits.filter((fruit) => !fruit.isDecayed);
https://stackoverflow.com/questions/42427393
复制相似问题