简体   繁体   English

TypeScript 中的条件属性和 switch 语句

[英]Conditional properties and switch statements in TypeScript

I defined these types:我定义了这些类型:

type ItemWithName = {
  type: "ItemWithName";
  name: string;
  a: { name: string } ;
};

type ItemWithValue = {
  type: string;
  name: string;
  b: { value: number } ;
};

export type Item = ItemWithName | ItemWithValue;

And I have a function to extract a certain value from an object:我有一个 function 从 object 中提取某个值:

const extractValue = (item: Item) => {
  switch (item.type) {
    case "ItemWithName":
      return item.a.name; // TS2339: Property 'a' does not exist on type 'Item'.
    case "ItemWithValue":
      return item.b.value; 
  }
};

But I get this error: TS2339: Property 'a' does not exist on type 'Item'.但我收到此错误: TS2339: Property 'a' does not exist on type 'Item'.

I'm not entirely sure how to make TypeScript understand that if the type of the object is "ItemWithValue", there's a property a.我不完全确定如何让 TypeScript 明白,如果 object 的类型是“ItemWithValue”,则有一个属性 a。

Note: this is a small abstraction of my particular issue, in reality I have several more of these types.注意:这是对我的特定问题的一个小抽象,实际上我还有更多这些类型。

The expected behaviour is that TypeScript detects that the item is of type ItemWithName if the object has a type value of "ItemWithName"如果 object 的类型值为"ItemWithName" ,则预期的行为是 TypeScript 检测到项目的类型为ItemWithName

Unfortunately this doesn't work currently with Typescript.不幸的是,这目前不适用于 Typescript。

Here's an issue on GitHub about a similar problem.这是 GitHub 关于类似问题的问题。

type-fest has a wrapper type LiteralUnion for the problem referenced in the issue. type-fest有一个包装类型LiteralUnion用于问题中引用的问题。 However you can't just use it like type Item = LiteralUnion<ItemWithName, ItemWithValue> .但是,您不能像type Item = LiteralUnion<ItemWithName, ItemWithValue>那样使用它。

So these are my two possibilities at the moment:所以这是我目前的两种可能性:

  1. Possibility: simply cast the type可能性:简单地转换类型
const extractValue = (item: Item) => {
  switch (item.type) {
    case "ItemWithName":
      const itemWithName = item as ItemWithName;
      return itemWithName.a.name;
    case "ItemWithValue":
      return item.b.value; 
  }
};
  1. Possibility: list all possible types可能性:列出所有可能的类型

Note: this is a small abstraction of my particular issue, in reality I have several more of these types.注意:这是对我的特定问题的一个小抽象,实际上我还有更多这些类型。

Instead of using而不是使用

type ItemWithValue = {
  type: string;
  name: string;
  b: { value: number } ;
};

you could create a type which unions all possible types like您可以创建一个联合所有可能类型的类型,例如

type ItemWithValue = {
  type: 'ItemWithValue' | 'OtherItemWithValue' | 'AgainAnItemWithValue';
  name: string;
  b: { value: number } ;
};

It would be really cool to use type: Exclude<string, 'ItemWithName'> .使用type: Exclude<string, 'ItemWithName'>真的很酷。 But this also would not work as you can see in this discussed question .但这也行不通,正如您在这个讨论的问题中看到的那样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM