[英]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
false
?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 | string
和number | 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
不是可接受的判别类型,因为number
和string
都不是文字类型。
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 | string
自
boolean | string
boolean | string
and number | boolean
boolean | string
和number | boolean
number | boolean
and 1 | string
number | boolean
和1 | 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 游乐场代码链接
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.