Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 无法调用其类型缺少调用签名的表达式_Javascript_Typescript_Types - Fatal编程技术网

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


您可以自己在官方网站上试用。

也许可以创建一个共享的
水果
界面,提供isDecayed
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);
正如最初由@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