【问题标题】:TS2339: Array.find in discriminated union not inferring type correctlyTS2339:Array.find 在可区分联合中未正确推断类型
【发布时间】:2020-03-24 18:10:50
【问题描述】:

在这个例子中,我有一个购物车,它可以装满不同种类的物品,在这个例子中是高尔夫球和高尔夫球杆,它们有自己的选择。

Typescript Playground link

下面的代码出现以下错误:

TS2339: Property 'color' does not exist on type '{ color: "blue" | "red" | "white"; } | { variant: "wedge" | "putter"; }'.
  Property 'color' does not exist on type '{ variant: "wedge" | "putter"; }'.
type ProductGolfBall = {
  type: "golfball";
  options: {
    color: "blue" | "red" | "white";
  };
};

type ProductGolfClub = {
  type: "golfclub";
  options: {
    variant: "wedge" | "putter";
  };
};

type CartItem = ProductGolfBall | ProductGolfClub;
type CartItems = Array<CartItem>;

const cart: CartItems = [
  {
    type: "golfball",
    options: {
      color: "blue"
    }
  },
  {
    type: "golfclub",
    options: {
      variant: "wedge"
    }
  },
  {
    type: "golfclub",
    options: {
      variant: "putter"
    }
  }
];

const golfball = cart.find((item) => item.type === "golfball");

if (golfball) { // Check that it's truthy
  // According to typescript this can still be either ProductGolfClub or ProductGolfBall
  console.log(golfball.type)
  console.log(golfball.options.color) // Produces the TS2339 error above
}

现在我只是不明白为什么 golfball 变量仍然可以是 ProductGolfClub 当查找操作仅对 type 属性为 golfball 的数组项返回 true 时。

我可以将 golfball 变量设置为 ProductGolfBall,但必须有其他方法让 typescript 了解变量的类型。

【问题讨论】:

    标签: typescript


    【解决方案1】:

    不幸的是,TS 无法从这种情况下开箱即用地制作类型保护。 但是您可以通过明确说明该功能将确保什么来手动完成,请考虑:

    function isGolfBall(item: CartItem): item is ProductGolfBall {
        return item.type === "golfball";
    }
    
    const golfball = cart.find(isGolfBall)
    
    if (golfball) { // Check that it's truthy
      console.log(golfball.type)
      console.log(golfball.options.color) // no error ?
    }
    

    最重要的是:item is ProductGolfBall,这意味着我们明确地说这个函数将是一个类型保护,它只会为ProductGolfBall传递(返回true)。

    内联解决方案也可以:

    const golfball = cart.find((item): item is ProductGolfBall => item.type === "golfball")
    

    【讨论】:

    • 我明白了。这似乎被称为user defined type guard。由于 TS 无法针对这种情况自动进行类型保护,是否有另一种编写此代码的方法可以省略用户定义的类型保护?
    • 我不这么认为。总的来说,我看到了实现您需要的可读且正确的方法。
    猜你喜欢
    • 2017-05-15
    • 1970-01-01
    • 1970-01-01
    • 2021-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-13
    相关资源
    最近更新 更多