@@ -17381,9 +17381,9 @@ namespace ts {
17381
17381
(target as UnionType).types.length <= 3 && maybeTypeOfKind(target, TypeFlags.Nullable)) {
17382
17382
const nullStrippedTarget = extractTypesOfKind(target, ~TypeFlags.Nullable);
17383
17383
if (!(nullStrippedTarget.flags & (TypeFlags.Union | TypeFlags.Never))) {
17384
- if (source === nullStrippedTarget) return Ternary.True;
17385
- target = nullStrippedTarget;
17384
+ target = getNormalizedType(nullStrippedTarget, /*writing*/ true);
17386
17385
}
17386
+ if (source === nullStrippedTarget) return Ternary.True;
17387
17387
}
17388
17388
17389
17389
if (relation === comparableRelation && !(target.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(target, source, relation) ||
@@ -17975,8 +17975,21 @@ namespace ts {
17975
17975
if (target.flags & TypeFlags.Intersection) {
17976
17976
return typeRelatedToEachType(getRegularTypeOfObjectLiteral(source), target as IntersectionType, reportErrors, IntersectionState.Target);
17977
17977
}
17978
- // Source is an intersection. Check to see if any constituents of the intersection are immediately related
17979
- // to the target.
17978
+ // Source is an intersection. For the comparable relation, if the target is a primitive type we hoist the
17979
+ // constraints of all non-primitive types in the source into a new intersection. We do this because the
17980
+ // intersection may further constrain the constraints of the non-primitive types. For example, given a type
17981
+ // parameter 'T extends 1 | 2', the intersection 'T & 1' should be reduced to '1' such that it doesn't
17982
+ // appear to be comparable to '2'.
17983
+ if (relation === comparableRelation && target.flags & TypeFlags.Primitive) {
17984
+ const constraints = sameMap((<IntersectionType>source).types, t => t.flags & TypeFlags.Primitive ? t : getBaseConstraintOfType(t) || unknownType);
17985
+ if (constraints !== (<IntersectionType>source).types) {
17986
+ source = getIntersectionType(constraints);
17987
+ if (!(source.flags & TypeFlags.Intersection)) {
17988
+ return isRelatedTo(source, target, /*reportErrors*/ false);
17989
+ }
17990
+ }
17991
+ }
17992
+ // Check to see if any constituents of the intersection are immediately related to the target.
17980
17993
//
17981
17994
// Don't report errors though. Checking whether a constituent is related to the source is not actually
17982
17995
// useful and leads to some confusing error messages. Instead it is better to let the below checks
@@ -19738,6 +19751,15 @@ namespace ts {
19738
19751
return !!(type.flags & TypeFlags.Unit);
19739
19752
}
19740
19753
19754
+ function isUnitLikeType(type: Type): boolean {
19755
+ return type.flags & TypeFlags.Intersection ? some((<IntersectionType>type).types, isUnitType) :
19756
+ !!(type.flags & TypeFlags.Unit);
19757
+ }
19758
+
19759
+ function extractUnitType(type: Type) {
19760
+ return type.flags & TypeFlags.Intersection ? find((<IntersectionType>type).types, isUnitType) || type : type;
19761
+ }
19762
+
19741
19763
function isLiteralType(type: Type): boolean {
19742
19764
return type.flags & TypeFlags.Boolean ? true :
19743
19765
type.flags & TypeFlags.Union ? type.flags & TypeFlags.EnumLiteral ? true : every((<UnionType>type).types, isUnitType) :
@@ -21721,14 +21743,6 @@ namespace ts {
21721
21743
return declaredType;
21722
21744
}
21723
21745
21724
- function getTypeFactsOfTypes(types: Type[]): TypeFacts {
21725
- let result: TypeFacts = TypeFacts.None;
21726
- for (const t of types) {
21727
- result |= getTypeFacts(t);
21728
- }
21729
- return result;
21730
- }
21731
-
21732
21746
function isFunctionObjectType(type: ObjectType): boolean {
21733
21747
// We do a quick check for a "bind" property before performing the more expensive subtype
21734
21748
// check. This gives us a quicker out in the common case where an object type is not a function.
@@ -21800,8 +21814,11 @@ namespace ts {
21800
21814
return !isPatternLiteralType(type) ? getTypeFacts(getBaseConstraintOfType(type) || unknownType) :
21801
21815
strictNullChecks ? TypeFacts.NonEmptyStringStrictFacts : TypeFacts.NonEmptyStringFacts;
21802
21816
}
21803
- if (flags & TypeFlags.UnionOrIntersection) {
21804
- return getTypeFactsOfTypes((<UnionOrIntersectionType>type).types);
21817
+ if (flags & TypeFlags.Union) {
21818
+ return reduceLeft((<UnionType>type).types, (facts, t) => facts | getTypeFacts(t), TypeFacts.None);
21819
+ }
21820
+ if (flags & TypeFlags.Intersection) {
21821
+ return reduceLeft((<UnionType>type).types, (facts, t) => facts & getTypeFacts(t), TypeFacts.All);
21805
21822
}
21806
21823
return TypeFacts.All;
21807
21824
}
@@ -23134,8 +23151,7 @@ namespace ts {
23134
23151
return replacePrimitivesWithLiterals(filterType(type, filterFn), valueType);
23135
23152
}
23136
23153
if (isUnitType(valueType)) {
23137
- const regularType = getRegularTypeOfLiteralType(valueType);
23138
- return filterType(type, t => isUnitType(t) ? !areTypesComparable(t, valueType) : getRegularTypeOfLiteralType(t) !== regularType);
23154
+ return filterType(type, t => !(isUnitLikeType(t) && areTypesComparable(t, valueType)));
23139
23155
}
23140
23156
return type;
23141
23157
}
@@ -23217,7 +23233,7 @@ namespace ts {
23217
23233
if (!hasDefaultClause) {
23218
23234
return caseType;
23219
23235
}
23220
- const defaultType = filterType(type, t => !(isUnitType (t) && contains(switchTypes, getRegularTypeOfLiteralType(t ))));
23236
+ const defaultType = filterType(type, t => !(isUnitLikeType (t) && contains(switchTypes, getRegularTypeOfLiteralType(extractUnitType(t) ))));
23221
23237
return caseType.flags & TypeFlags.Never ? defaultType : getUnionType([caseType, defaultType]);
23222
23238
}
23223
23239
0 commit comments