首页 > 解决方案 > 类型保护可以应用于接口的成员吗?

问题描述

我有以下代码:

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)。

IOnlyLikeApples有一个不同于switch.

标签: typescript

解决方案


在尝试将开关用作类型保护之前,我遇到过这个问题。这取决于打字稿在开关开始时将类型分配给对象o并且从不重新评估它的事实。如果您查看分支的oo.fruit内部的值case Fruit.Apple,您会看到 TS 知道它o.fruit是 type Fruit.Apple,但仍然认为 typeoFruitWrapper并且没有添加任何其他内容。

有很多方法可以解决这个问题。最简单也是最草率的做法是简单地断言你所知道的:IOnlyLikeApples(o as FruitWrapper & { fruit: Fruit.Apple });

你必须使用switch语句吗?如果您可以在 an 内使用类型保护重写它,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;
    }
}

游乐场链接


推荐阅读