-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove empty intersection types in union types #18438
Conversation
src/compiler/checker.ts
Outdated
@@ -7302,7 +7302,11 @@ namespace ts { | |||
if (flags & TypeFlags.Null) typeSet.containsNull = true; | |||
if (!(flags & TypeFlags.ContainsWideningType)) typeSet.containsNonWideningType = true; | |||
} | |||
else if (!(flags & TypeFlags.Never)) { | |||
else if (!(flags & TypeFlags.Never || flags & TypeFlags.Intersection && every((<IntersectionType>type).types, isUnitType))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than checking if every
type is unit, is it not sufficient to check if any two members are unit? number & 3 & 4
is as vacuous as 3 & 4
, right?
what about tag types #4895? type CustomerId = number & 'customer-id'; |
Use |
Is |
An intersection of distinct unit types (such as
'a' & 'b' & 'c'
) is effectively the same asnever
because it has en empty set of possible values. We allow such types to exist primarily to make it easier to discover their origin (e.g. an intersection of object types containing two properties with the same name). However, when intersecting unions of unit types, the normalization introduced by #11717 ends up making the types very noisy. For example(0 | 1 | 2) & (1 | 2 | 3)
becomes1 | 2 | (0 & 1) | (0 & 2) | (0 & 3) | (1 & 2) | (1 & 3) | (2 & 1) | (2 & 3)
.Likewise, when intersecting
{ a: string } | undefined
and{ b: number } | undefined
(similar to #18210), normalization produces a union of{ a: string } & { b: number }
,{ a: string } & undefined
,undefined & { b: number }
andundefined
. The middle two have empty sets of values, but trip up property accesses through values of the union type.With this PR we now remove an intersection type from a union type if
null
orundefined
).Some examples:
We could in theory be more aggressive about removing empty intersection types, but we don't want to break code that uses intersections to "tag" primitive types.
This implements parts of what is suggested in #16386 and fixes #18210.