Erd*_*dem 66 javascript types typescript
我有苹果和梨 - 都有一个isDecayed属性:
interface Apple {
color: string;
isDecayed: boolean;
}
interface Pear {
weight: number;
isDecayed: boolean;
}
Run Code Online (Sandbox Code Playgroud)
这两种类型都可以在我的水果篮中(多次):
interface FruitBasket {
apples: Apple[];
pears: Pear[];
}
Run Code Online (Sandbox Code Playgroud)
我们假设现在我的篮子是空的:
const fruitBasket: FruitBasket = { apples: [], pears: [] };
Run Code Online (Sandbox Code Playgroud)
现在我们随机抽出一种:
const key: keyof FruitBasket = Math.random() > 0.5 ? 'apples': 'pears';
const fruits = fruitBasket[key];
Run Code Online (Sandbox Code Playgroud)
当然,没有人喜欢朽烂的水果,所以我们只选择新鲜水果:
const freshFruits = fruits.filter((fruit) => !fruit.isDecayed);
Run Code Online (Sandbox Code Playgroud)
不幸的是,Typescript告诉我:
无法调用类型缺少调用签名的表达式.输入'((callbackfn :(值:Apple,索引:数字,数组:Apple [])=> any,thisArg?:any)=> Apple [])| ......'没有兼容的呼号.
这里有什么问题 - 只是因为Typescript不喜欢新鲜水果,或者这是一个Typescript错误?
您可以在官方的Typescript Repl中自己尝试一下.
Sef*_*efe 78
TypeScript支持结构类型(也称为duck typing),这意味着类型在共享相同成员时是兼容的.您的问题是,Apple并且Pear不要共享其所有成员,这意味着它们不兼容.但是它们与仅具有该isDecayed: boolean成员的另一种类型兼容.由于结构打字,你不"需要继承Apple和Pear从这样的接口.
有不同的方法来分配这种兼容类型:
在变量声明期间分配类型
此语句隐式输入Apple[] | Pear[]:
const fruits = fruitBasket[key];
Run Code Online (Sandbox Code Playgroud)
您可以在变量声明中明确使用兼容类型:
const fruits: { isDecayed: boolean }[] = fruitBasket[key];
Run Code Online (Sandbox Code Playgroud)
为了获得额外的可重用性,您还可以先定义类型,然后在声明中使用它(请注意,不需要更改Apple和Pear接口):
type Fruit = { isDecayed: boolean };
const fruits: Fruit[] = fruitBasket[key];
Run Code Online (Sandbox Code Playgroud)
转换为兼容类型以进行操作
给定解决方案的问题是它改变了fruits变量的类型.这可能不是你想要的.为避免这种情况,您可以在操作之前将数组缩小到兼容类型,然后将类型设置回与以下相同的类型fruits:
const fruits: fruitBasket[key];
const freshFruits = (fruits as { isDecayed: boolean }[]).filter(fruit => !fruit.isDecayed) as typeof fruits;
Run Code Online (Sandbox Code Playgroud)
或者使用可重复使用的Fruit类型:
type Fruit = { isDecayed: boolean };
const fruits: fruitBasket[key];
const freshFruits = (fruits as Fruit[]).filter(fruit => !fruit.isDecayed) as typeof fruits;
Run Code Online (Sandbox Code Playgroud)
这种解决方案的优点是既,fruits以及freshFruits将类型Apple[] | Pear[].
正如@peter 在评论中最初链接的github 问题中所述:
const freshFruits = (fruits as (Apple | Pear)[]).filter((fruit: (Apple | Pear)) => !fruit.isDecayed);
Run Code Online (Sandbox Code Playgroud)