简体   繁体   English

打字稿 - 基于 for 列表中的值的条件类型

[英]Typescript - conditional types based on value in a for of list

So these are my types:所以这些是我的类型:

export type typeOne = {
  A: string;
  B: string;
};

export type typeTwo = {
  A: string;
  C: string;
};

export type Result = typeOne | typeTwo; //condition 

And this is the use case:这是用例:

for (const item: Result of list) {
   const something = item.B ? 'B exsist' : item.C;
   return something;
}

It keeps returning error:它不断返回错误:

TS2339: Property 'B' does not exist on type 'Result'. TS2339:“结果”类型上不存在属性“B”。 Property 'B' does not exist on type 'typeTwo'.类型“typeTwo”上不存在属性“B”。

and also for the other one:还有另一个:

TS2339: Property 'C' does not exist on type 'Result'. TS2339:“结果”类型上不存在属性“C”。 Property 'C' does not exist on type 'typeOne'.类型“typeOne”上不存在属性“C”。

Do you have any idea how can I fix this?你知道我该如何解决这个问题吗?

Note : The following error is also happening for the loop:注意:循环也会发生以下错误:

TS2483: The left-hand side of a 'for...of' statement cannot use a type annotation. TS2483:“for...of”语句的左侧不能使用类型注释。

You can use an in type guard to discriminate a union of object types with unequal keys:您可以使用in类型保护来区分具有不相等键的对象类型的联合:

for (const item: Result of list) {
   const something = "B" in item ? 'B exsist' : item.C;
   return something;
}

Playground link 游乐场链接

One of the nuances of TypeScript is that if you have a union type of objects, you can only access the fields that are common between them. TypeScript 的一个细微差别是,如果你有一个联合类型的对象,你只能访问它们之间的公共字段。 It is common to use this technique to add a common field that can tell the two apart.使用这种技术来添加一个可以区分两者的公共字段是很常见的。 For instance:例如:

export type typeOne = {
  type: 'one';
  A: string;
  B: string;
};

export type typeTwo = {
  type: 'two'
  A: string;
  C: string;
};

export type Result = typeOne | typeTwo; //condition 

for (const item: Result of list) {
   const something = item.type === 'one' ? 'B exists' : item.C;
   return something;
}

In this case, type acts as a discriminator.在这种情况下, type充当鉴别器。 Read more here: https://basarat.gitbook.io/typescript/type-system/discriminated-unions在此处阅读更多信息: https : //basarat.gitbook.io/typescript/type-system/discriminated-unions


Alternatively, you can create a custom type guard to differentiate between the two types.或者,您可以创建自定义类型保护来区分这两种类型。 This involves a function that takes your union type and evaluates at runtime if the value is of a particular type.这涉及一个函数,该函数接受您的联合类型并在运行时评估该值是否为特定类型。 You can use a type assertion to access a non-shared field in the union:您可以使用类型断言访问联合中的非共享字段:

function isTypeOne(result: Result): result is typeOne {
  return (result as typeOne).B !== undefined;
}

for (const item: Result of list) {
   const something = isTypeOne(item) ? 'B exists' : item.C;
   return something;
}

Here, if isTypeOne fails, typeOne can be safely eliminated from Result , thus the type is inferred as typeTwo .在这里,如果isTypeOne失败, typeOne可以安全地从Result消除,因此类型被推断为typeTwo

Regarding the last error you mentioned:关于您提到的最后一个错误:

"TS2483: The left-hand side of a 'for...of' statement cannot use a type annotation." “TS2483:'for...of' 语句的左侧不能使用类型注释。”

The Result type definition should be part of your declaration of list . Result类型定义应该是list声明的一部分。 That way, there is no need to specify that the left-hand side of the statement is a Result .这样,就无需指定语句的左侧是Result

For example, assuming list is an array:例如,假设list是一个数组:

const list: Array<Result> = [{A: 'foo', B: 'bar'}, {A: 'foo', C: 'baz'}]
for (const item of list) {
  // Run code from other answers here
}

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

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