首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >类型保护可以应用于接口的成员吗?

类型保护可以应用于接口的成员吗?
EN

Stack Overflow用户
提问于 2020-09-25 03:39:19
回答 2查看 35关注 0票数 0

我有以下代码:

代码语言:javascript
运行
复制
enum Fruit {
  Apple,
  Banana,
}

interface FruitWrapper {
  fruit: Fruit;
  //...
}

function IOnlyLikeApples(o: FruitWrapper & { fruit: Fruit.Apple }) { ... }

和一个switch作为我的类型保护

代码语言:javascript
运行
复制
const o: ISomeInterface = getFruit();
switch(o.fruit) {
  case Fruit.Apple:
    IOnlyLikeApples(o);
    break;
}

在将o传递给IOnlyLikeApples时,我得到以下错误

代码语言:javascript
运行
复制
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仍然拒绝此代码。

我能想到的唯一解决方案是这样的:

代码语言:javascript
运行
复制
const o: ISomeInterface = getFruit();
const f = o.fruit;
switch(f) {
  case Fruit.Apple:
    IOnlyLikeApples({ ...o,  fruit: f });
    break;
}

这是丑陋和粗俗的(在这一点上,不值得编译器支持来帮助IOnlyLikeApples的调用者)。

switch相比,IOnlyLikeApples有不同的维护者。

EN

回答 2

Stack Overflow用户

发布于 2020-09-25 07:08:52

我有点让它工作了,但它不是那么漂亮:

代码语言:javascript
运行
复制
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);
}

Playground link

票数 0
EN

Stack Overflow用户

发布于 2020-09-25 08:40:30

我以前在尝试使用开关作为类型保护时遇到过这个问题。这是因为typescript在切换开始时将类型赋值给对象o,而不会重新计算它。如果查看case Fruit.Apple分支中的oo.fruit的值,就会发现TS知道o.fruit的类型是Fruit.Apple,但仍然认为o的类型是FruitWrapper,并且没有向其添加任何其他内容。

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

您必须使用switch语句吗?如果你可以在if中使用类型保护重写它,那么你就不会有这个问题了。

代码语言:javascript
运行
复制
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不能在接口中指定,但它能够处理联合中的区分。这可以很好地工作:

代码语言:javascript
运行
复制
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;
    }
}

Playground Link

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64053292

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档