我有以下代码:
enum Fruit {
Apple,
Banana,
}
interface FruitWrapper {
fruit: Fruit;
//...
}
function IOnlyLikeApples(o: FruitWrapper & { fruit: Fruit.Apple }) { ... }和一个switch作为我的类型保护
const o: ISomeInterface = getFruit();
switch(o.fruit) {
case Fruit.Apple:
IOnlyLikeApples(o);
break;
}在将o传递给IOnlyLikeApples时,我得到以下错误
Argument of type 'FruitWrapper' is not assignable to parameter of type 'FruitWrapper & { fruit: Fruit.Apple; }'.
Type 'FruitWrapper' is not assignable to type '{ fruit: Fruit.Apple; }'.
Types of property 'fruit' are incompatible.
Type 'Fruit' is not assignable to type 'Fruit.Apple'.为什么TS会抱怨这个?有一种观点认为,即使引用o是常量,它的成员也不是常量,但是o.fruit不会被重新分配。即使我使用interface FruitWrapper { readonly fruit: Fruit; },TS仍然拒绝此代码。
我能想到的唯一解决方案是这样的:
const o: ISomeInterface = getFruit();
const f = o.fruit;
switch(f) {
case Fruit.Apple:
IOnlyLikeApples({ ...o, fruit: f });
break;
}这是丑陋和粗俗的(在这一点上,不值得编译器支持来帮助IOnlyLikeApples的调用者)。
与switch相比,IOnlyLikeApples有不同的维护者。
发布于 2020-09-25 07:08:52
我有点让它工作了,但它不是那么漂亮:
const getFruit = () => {
if (Math.random() > 0.5) {
return {
fruit: Fruit.Banana,
misc: 'asd'
// the as const is needed here. Unfortunate.
} as const
} else {
return {
fruit: Fruit.Apple,
misc: 'asd'
// and here. Unfortunate again.
} as const
}
}
const o = getFruit();
switch(o.fruit) {
case Fruit.Apple:
IOnlyLikeApples(o);
break;
case Fruit.Banana:
IOnlyLikeApples(o);
}发布于 2020-09-25 08:40:30
我以前在尝试使用开关作为类型保护时遇到过这个问题。这是因为typescript在切换开始时将类型赋值给对象o,而不会重新计算它。如果查看case Fruit.Apple分支中的o和o.fruit的值,就会发现TS知道o.fruit的类型是Fruit.Apple,但仍然认为o的类型是FruitWrapper,并且没有向其添加任何其他内容。
有很多方法可以解决这个问题。最简单、最草率的方法是简单地断言您所知道的内容:IOnlyLikeApples(o as FruitWrapper & { fruit: Fruit.Apple });
您必须使用switch语句吗?如果你可以在if中使用类型保护重写它,那么你就不会有这个问题了。
type Apple = FruitWrapper & { fruit: Fruit.Apple };
const isApple = (o: FruitWrapper): o is Apple => {
return o.fruit === Fruit.Apple;
}
const handleFruit = ( o: FruitWrapper ) => {
if ( isApple(o) ) {
IOnlyLikeApples(o);
} else {
/*...*/
}
}另一种选择是将水果设置为联合类型,这取决于您的数据是否合理。switch不能在接口中指定,但它能够处理联合中的区分。这可以很好地工作:
type Apple = FruitWrapper & { fruit: Fruit.Apple };
type Banana = FruitWrapper & { fruit: Fruit.Banana };
type FruitUnion = Apple | Banana;
const handleFruit = ( o: FruitUnion ) => {
switch(o.fruit) {
case Fruit.Apple:
IOnlyLikeApples(o);
break;
case Fruit.Banana:
/* ... */
break;
}
}https://stackoverflow.com/questions/64053292
复制相似问题