简体   繁体   English

为什么 [number | 字符串] 扩展 [数字] | [字符串] 在 typescript 中?

[英]Why doesn't [number | string] extends [number] | [string] in typescript?

These are true:这些是真的:

type A = [boolean | string] extends [boolean] | [string] ? true : false // true
type B = [number | boolean] extends [number] | [boolean] ? true : false // true
type C = [1 | string] extends [1] | [string] ? true : false // true

But this is false:但这是错误的:

type D = [number | string] extends [number] | [string] ? true : false // false
  1. How does the TypeScript compiler deal with a tuple type in a condition? TypeScript 编译器如何处理条件中的元组类型? Does it distribute one tuple into many tuples?它是否将一个元组分配到许多元组中?
  2. Why is type D false ?为什么 D 型是false的?

Before TypeScript 4.0, all of those conditional types evaluated to false .在 TypeScript 4.0 之前,所有这些条件类型的计算结果都是false The issue here has to do with how the compiler treats object types with union-typed properties differently when the union in question is or is not considered the type of a discriminant of a discriminated union .这里的问题与编译器如何处理object具有联合类型属性的类型有关,当所讨论的联合被视为或不被视为discriminated union判别式类型时。

Since TypeScript 3.2 introduced support for non-unit types as discriminants , a union can be a discriminated union as long as some common member of the union has a property of a literal type (or a union of such types).自 TypeScript 3.2 引入了对非单位类型作为判别式的支持,只要联合的某些公共成员具有文字类型(或此类类型的联合)的属性,联合就可以是可区分联合。

The types boolean | string类型boolean | string boolean | string and number | boolean boolean | stringnumber | boolean number | boolean are acceptable discriminant properties, since boolean is shorthand for the union true | false number | boolean是可接受的判别属性,因为boolean是联合true | false的简写true | false , each of which is a literal type. true | false ,每个都是文字类型。 1 | string 1 | string is also an acceptable discriminant, since 1 is a literal type. 1 | string也是可接受的判别式,因为1是文字类型。 On the other hand, number | string另一方面, number | string number | string is not an acceptable discriminant type, since neither number nor string is a literal type. number | string不是可接受的判别类型,因为numberstring都不是文字类型。


In general, TypeScript does not consider an object type with a union typed property assignable to a union of object types.通常,TypeScript 不考虑具有联合类型属性的 object 类型可分配给 object 类型的联合。 That is, unions do not in general propagate upward from properties to top-level objects:也就是说,联合通常不会从属性向上传播到顶级对象:

const x: { a: RegExp | Date } = { a: Math.random() < 0.5 ? /abc/ : new Date() };
const y: { a: RegExp } | { a: Date } = x; // error!

This behavior can be annoying, especially in situations where the type you're trying to assign to is a discriminated union .这种行为可能很烦人,尤其是在您尝试分配给的类型是受歧视的联合的情况下。 So TypeScript 3.5 introduced support for "smarter" union type checking via microsoft/TypeScript#30779 where you can do such assignments as long as the target type is a discriminated union.因此 TypeScript 3.5 通过microsoft/TypeScript#30779引入了对“更智能”联合类型检查的支持,只要目标类型是可区分的联合,您就可以进行此类分配。 So the following assignment works as of TypeScript 3.5:因此,以下作业从 TypeScript 3.5 起有效:

const v: { a: RegExp | "abc" } = { a: Math.random() < 0.5 ? /abc/ : "abc" };
const w: { a: RegExp } | { a: "abc" } = v; // error in TS3.4-, okay in TS3.5+

Since "abc" is a literal type, then the type of w is a discriminated union, and therefore the assignment is accepted.由于"abc"是文字类型,因此w的类型是可区分的联合,因此接受赋值。

From TypeScript 3.5 through TypeScript 3.9, those conditional types still all evaluated to false , because this change in assignability was not fully reflected in the type system, such as when you write conditional types.从 TypeScript 3.5 到 TypeScript 3.9,那些条件类型仍然全部评估为false ,因为这种可分配性的变化没有完全反映在类型系统中,例如当您编写条件类型时。 The fix to this, microsoft/TypeScript#39393 , was released with TypeScript 4.0.对此的修复, microsoft/TypeScript#39393 ,与 TypeScript 4.0 一起发布。 Now the type system also sees that objects-with-union-properties are assignable to appropriate discriminated unions:现在类型系统也看到 objects-with-union-properties 可以分配给适当的可区分联合:

type A = [boolean | string] extends [boolean] | [string] ? true : false 
// false in TS3.9-, true in TS4.0+
type B = [number | boolean] extends [number] | [boolean] ? true : false 
// false in TS3.9-, true in TS4.0+
type C = [1 | string] extends [1] | [string] ? true : false 
// false in TS3.9-, true in TS4.0+
type D = [number | string] extends [number] | [string] ? true : false 
// false

One-tuples like [X] are similar to object types like {0: X} , so [X] | [Y][X]这样的元组类似于像{0: X}这样的 object 类型,所以[X] | [Y] [X] | [Y] is a discriminated union if {0: X} | {0: Y}如果{0: X} | {0: Y} [X] | [Y]是可区分联合{0: X} | {0: Y} is. {0: X} | {0: Y}是。 And since boolean | stringboolean | string boolean | string and number | boolean boolean | stringnumber | boolean number | boolean and 1 | string number | boolean1 | string 1 | string are discriminant types, the assignment succeeds. 1 | string为判别类型,赋值成功。 And since number | string并且由于number | string number | string is not a discriminant type, the assignment fails. number | string不是判别类型,赋值失败。

Playground link to code 游乐场代码链接

Playground link to code v3.9 游乐场链接到代码 v3.9

Playground link to code v3.3 游乐场链接到代码 v3.3

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

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