@@ -9522,44 +9522,13 @@ namespace ts {
95229522 return false;
95239523 }
95249524
9525- // Return true if the given intersection type contains
9526- // more than one unit type or,
9527- // an object type and a nullable type (null or undefined), or
9528- // a string-like type and a type known to be non-string-like, or
9529- // a number-like type and a type known to be non-number-like, or
9530- // a symbol-like type and a type known to be non-symbol-like, or
9531- // a void-like type and a type known to be non-void-like, or
9532- // a non-primitive type and a type known to be primitive.
9533- function isEmptyIntersectionType(type: IntersectionType) {
9534- let combined: TypeFlags = 0;
9535- for (const t of type.types) {
9536- if (t.flags & TypeFlags.Unit && combined & TypeFlags.Unit) {
9537- return true;
9538- }
9539- combined |= t.flags;
9540- if (combined & TypeFlags.Nullable && combined & (TypeFlags.Object | TypeFlags.NonPrimitive) ||
9541- combined & TypeFlags.NonPrimitive && combined & (TypeFlags.DisjointDomains & ~TypeFlags.NonPrimitive) ||
9542- combined & TypeFlags.StringLike && combined & (TypeFlags.DisjointDomains & ~TypeFlags.StringLike) ||
9543- combined & TypeFlags.NumberLike && combined & (TypeFlags.DisjointDomains & ~TypeFlags.NumberLike) ||
9544- combined & TypeFlags.BigIntLike && combined & (TypeFlags.DisjointDomains & ~TypeFlags.BigIntLike) ||
9545- combined & TypeFlags.ESSymbolLike && combined & (TypeFlags.DisjointDomains & ~TypeFlags.ESSymbolLike) ||
9546- combined & TypeFlags.VoidLike && combined & (TypeFlags.DisjointDomains & ~TypeFlags.VoidLike)) {
9547- return true;
9548- }
9549- }
9550- return false;
9551- }
9552-
95539525 function addTypeToUnion(typeSet: Type[], includes: TypeFlags, type: Type) {
95549526 const flags = type.flags;
95559527 if (flags & TypeFlags.Union) {
95569528 return addTypesToUnion(typeSet, includes, (<UnionType>type).types);
95579529 }
9558- // We ignore 'never' types in unions. Likewise, we ignore intersections of unit types as they are
9559- // another form of 'never' (in that they have an empty value domain). We could in theory turn
9560- // intersections of unit types into 'never' upon construction, but deferring the reduction makes it
9561- // easier to reason about their origin.
9562- if (!(flags & TypeFlags.Never || flags & TypeFlags.Intersection && isEmptyIntersectionType(<IntersectionType>type))) {
9530+ // We ignore 'never' types in unions
9531+ if (!(flags & TypeFlags.Never)) {
95639532 includes |= flags & TypeFlags.IncludesMask;
95649533 if (flags & TypeFlags.StructuredOrInstantiable) includes |= TypeFlags.IncludesStructuredOrInstantiable;
95659534 if (type === wildcardType) includes |= TypeFlags.IncludesWildcard;
@@ -9783,13 +9752,18 @@ namespace ts {
97839752 }
97849753 }
97859754 else {
9786- includes |= flags & TypeFlags.IncludesMask;
97879755 if (flags & TypeFlags.AnyOrUnknown) {
97889756 if (type === wildcardType) includes |= TypeFlags.IncludesWildcard;
97899757 }
97909758 else if ((strictNullChecks || !(flags & TypeFlags.Nullable)) && !contains(typeSet, type)) {
9759+ if (type.flags & TypeFlags.Unit && includes & TypeFlags.Unit) {
9760+ // We have seen two distinct unit types which means we should reduce to an
9761+ // empty intersection. Adding TypeFlags.NonPrimitive causes that to happen.
9762+ includes |= TypeFlags.NonPrimitive;
9763+ }
97919764 typeSet.push(type);
97929765 }
9766+ includes |= flags & TypeFlags.IncludesMask;
97939767 }
97949768 return includes;
97959769 }
@@ -9905,7 +9879,23 @@ namespace ts {
99059879 function getIntersectionType(types: ReadonlyArray<Type>, aliasSymbol?: Symbol, aliasTypeArguments?: ReadonlyArray<Type>): Type {
99069880 const typeSet: Type[] = [];
99079881 const includes = addTypesToIntersection(typeSet, 0, types);
9908- if (includes & TypeFlags.Never) {
9882+ // An intersection type is considered empty if it contains
9883+ // the type never, or
9884+ // more than one unit type or,
9885+ // an object type and a nullable type (null or undefined), or
9886+ // a string-like type and a type known to be non-string-like, or
9887+ // a number-like type and a type known to be non-number-like, or
9888+ // a symbol-like type and a type known to be non-symbol-like, or
9889+ // a void-like type and a type known to be non-void-like, or
9890+ // a non-primitive type and a type known to be primitive.
9891+ if (includes & TypeFlags.Never ||
9892+ strictNullChecks && includes & TypeFlags.Nullable && includes & (TypeFlags.Object | TypeFlags.NonPrimitive | TypeFlags.IncludesEmptyObject) ||
9893+ includes & TypeFlags.NonPrimitive && includes & (TypeFlags.DisjointDomains & ~TypeFlags.NonPrimitive) ||
9894+ includes & TypeFlags.StringLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.StringLike) ||
9895+ includes & TypeFlags.NumberLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.NumberLike) ||
9896+ includes & TypeFlags.BigIntLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.BigIntLike) ||
9897+ includes & TypeFlags.ESSymbolLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.ESSymbolLike) ||
9898+ includes & TypeFlags.VoidLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.VoidLike)) {
99099899 return neverType;
99109900 }
99119901 if (includes & TypeFlags.Any) {
0 commit comments