Javascript 无法调用其类型缺少调用签名的表达式
我有苹果和梨-都有Javascript 无法调用其类型缺少调用签名的表达式,javascript,typescript,types,Javascript,Typescript,Types,我有苹果和梨-都有isDecayed属性: interface Apple { color: string; isDecayed: boolean; } interface Pear { weight: number; isDecayed: boolean; } 这两种类型都可以放在我的果篮中(多次): 现在让我们假设我的篮子是空的: const fruitBasket: FruitBasket = { apples: [], pears: [] }; 现在
isDecayed
属性:
interface Apple {
color: string;
isDecayed: boolean;
}
interface Pear {
weight: number;
isDecayed: boolean;
}
这两种类型都可以放在我的果篮中(多次):
现在让我们假设我的篮子是空的:
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:(值:Apple,索引:number,数组:Apple[])=>any,thisArg?:any=>Apple[])|……”没有兼容的呼叫签名
这里出了什么问题-是Typescript不喜欢新鲜水果还是这是一个Typescript bug
您可以自己在官方网站上试用。也许可以创建一个共享的
水果
界面,提供isDecayedfruits
现在是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);
正如最初由@peter在评论中链接的文章中提到的:
const freshFruits = (fruits as (Apple | Pear)[]).filter((fruit: (Apple | Pear)) => !fruit.isDecayed);
TypeScript支持结构类型(也称为duck类型),这意味着。你的问题是,
Apple
和Pear
没有共享它们的所有成员,这意味着它们不兼容。但是,它们与另一种仅具有isDecayed:boolean
成员的类型兼容。由于结构类型,您不需要从这样的接口继承Apple
和Pear
分配此类兼容类型的方法有多种:
在变量声明期间分配类型
此语句隐式键入到Apple[]| Pear[]
:
const fruits = fruitBasket[key];
您只需在变量声明中显式使用兼容类型:
const fruits: { isDecayed: boolean }[] = fruitBasket[key];
为了增加可重用性,您还可以先定义类型,然后在声明中使用它(注意,Apple
和Pear
接口不需要更改):
转换为操作的兼容类型
给定解决方案的问题在于它更改了fruits
变量的类型。这可能不是你想要的。为了避免这种情况,您可以在操作之前将数组缩小到兼容的类型,然后将该类型设置回与fruits
相同的类型:
const fruits: fruitBasket[key];
const freshFruits = (fruits as { isDecayed: boolean }[]).filter(fruit => !fruit.isDecayed) as typeof fruits;
或使用可重复使用的水果
类型:
type Fruit = { isDecayed: boolean };
const fruits: fruitBasket[key];
const freshFruits = (fruits as Fruit[]).filter(fruit => !fruit.isDecayed) as typeof fruits;
此解决方案的优点是,
fruits
和freshFruits
都属于Apple[]| Pear[]
类型。我对JS库Numeric也有同样的问题。修复方法是使用以下命令再次安装打字:
npm install --save @types/numeral
尝试过google任何原因后,您都无法使用
isDecayed
属性扩展泛型Fruit
接口,然后将Fruit声明为Fruit[]
?奇怪……如果您显式地将键设置为string
即常量键:string=Math.random()>0.5,则不会出现错误苹果:“梨”代码>^之所以发生,是因为如果没有明确的索引签名,返回类型将是any
,从而避免了此问题。我没有苹果和梨的混合数组,而是苹果数组或梨数组。我使用Typescript的原因相同:构造代码,我或第三方能够更好地理解代码在做什么,以及代码在处理什么。苹果和梨子的混合阵列将永远不会出现在这个阵列中。那么,为什么我要将它定义为一个混合数组呢?如果我错了,请纠正我,但数组将包含苹果或梨的陈述不是错误的,它只是没有描述全部事实。你完全正确。但如果我有机会更详细地描述它,我想使用这种方法,这就是我不明白为什么Typescript将更详细的一个作为错误处理的原因。谢谢-这是我在此期间使用的解决方法,但对我来说,它仍然更像是一种黑客而不是真正的解决方案。这是唯一的办法吗?这种情况经常发生。你的水果篮
也可以是水果
的数组
type Fruit = { isDecayed: boolean };
const fruits: fruitBasket[key];
const freshFruits = (fruits as Fruit[]).filter(fruit => !fruit.isDecayed) as typeof fruits;
npm install --save @types/numeral