@@ -17947,8 +17947,21 @@ namespace ts {
17947
17947
if (target.flags & TypeFlags.Intersection) {
17948
17948
return typeRelatedToEachType(getRegularTypeOfObjectLiteral(source), target as IntersectionType, reportErrors, IntersectionState.Target);
17949
17949
}
17950
- // Source is an intersection. Check to see if any constituents of the intersection are immediately related
17951
- // to the target.
17950
+ // Source is an intersection. For the comparable relation, if the target is a primitive type we hoist the
17951
+ // constraints of all non-primitive types in the source into a new intersection. We do this because the
17952
+ // intersection may further constrain the constraints of the non-primitive types. For example, given a type
17953
+ // parameter 'T extends 1 | 2', the intersection 'T & 1' should be reduced to '1' such that it doesn't
17954
+ // appear to be comparable to '2'.
17955
+ if (relation === comparableRelation && target.flags & TypeFlags.Primitive) {
17956
+ const constraints = sameMap((<IntersectionType>source).types, t => t.flags & TypeFlags.Primitive ? t : getBaseConstraintOfType(t) || unknownType);
17957
+ if (constraints !== (<IntersectionType>source).types) {
17958
+ source = getIntersectionType(constraints);
17959
+ if (!(source.flags & TypeFlags.Intersection)) {
17960
+ return isRelatedTo(source, target, /*reportErrors*/ false);
17961
+ }
17962
+ }
17963
+ }
17964
+ // Check to see if any constituents of the intersection are immediately related to the target.
17952
17965
//
17953
17966
// Don't report errors though. Checking whether a constituent is related to the source is not actually
17954
17967
// useful and leads to some confusing error messages. Instead it is better to let the below checks
@@ -19680,6 +19693,15 @@ namespace ts {
19680
19693
return !!(type.flags & TypeFlags.Unit);
19681
19694
}
19682
19695
19696
+ function isUnitLikeType(type: Type): boolean {
19697
+ return type.flags & TypeFlags.Intersection ? some((<IntersectionType>type).types, isUnitType) :
19698
+ !!(type.flags & TypeFlags.Unit);
19699
+ }
19700
+
19701
+ function extractUnitType(type: Type) {
19702
+ return type.flags & TypeFlags.Intersection ? find((<IntersectionType>type).types, isUnitType) || type : type;
19703
+ }
19704
+
19683
19705
function isLiteralType(type: Type): boolean {
19684
19706
return type.flags & TypeFlags.Boolean ? true :
19685
19707
type.flags & TypeFlags.Union ? type.flags & TypeFlags.EnumLiteral ? true : every((<UnionType>type).types, isUnitType) :
@@ -21663,14 +21685,6 @@ namespace ts {
21663
21685
return declaredType;
21664
21686
}
21665
21687
21666
- function getTypeFactsOfTypes(types: Type[]): TypeFacts {
21667
- let result: TypeFacts = TypeFacts.None;
21668
- for (const t of types) {
21669
- result |= getTypeFacts(t);
21670
- }
21671
- return result;
21672
- }
21673
-
21674
21688
function isFunctionObjectType(type: ObjectType): boolean {
21675
21689
// We do a quick check for a "bind" property before performing the more expensive subtype
21676
21690
// check. This gives us a quicker out in the common case where an object type is not a function.
@@ -21742,8 +21756,11 @@ namespace ts {
21742
21756
return !isPatternLiteralType(type) ? getTypeFacts(getBaseConstraintOfType(type) || unknownType) :
21743
21757
strictNullChecks ? TypeFacts.NonEmptyStringStrictFacts : TypeFacts.NonEmptyStringFacts;
21744
21758
}
21745
- if (flags & TypeFlags.UnionOrIntersection) {
21746
- return getTypeFactsOfTypes((<UnionOrIntersectionType>type).types);
21759
+ if (flags & TypeFlags.Union) {
21760
+ return reduceLeft((<UnionType>type).types, (facts, t) => facts | getTypeFacts(t), TypeFacts.None);
21761
+ }
21762
+ if (flags & TypeFlags.Intersection) {
21763
+ return reduceLeft((<UnionType>type).types, (facts, t) => facts & getTypeFacts(t), TypeFacts.All);
21747
21764
}
21748
21765
return TypeFacts.All;
21749
21766
}
@@ -23075,8 +23092,7 @@ namespace ts {
23075
23092
return replacePrimitivesWithLiterals(filterType(type, filterFn), valueType);
23076
23093
}
23077
23094
if (isUnitType(valueType)) {
23078
- const regularType = getRegularTypeOfLiteralType(valueType);
23079
- return filterType(type, t => isUnitType(t) ? !areTypesComparable(t, valueType) : getRegularTypeOfLiteralType(t) !== regularType);
23095
+ return filterType(type, t => !(isUnitLikeType(t) && areTypesComparable(t, valueType)));
23080
23096
}
23081
23097
return type;
23082
23098
}
@@ -23158,7 +23174,7 @@ namespace ts {
23158
23174
if (!hasDefaultClause) {
23159
23175
return caseType;
23160
23176
}
23161
- const defaultType = filterType(type, t => !(isUnitType (t) && contains(switchTypes, getRegularTypeOfLiteralType(t ))));
23177
+ const defaultType = filterType(type, t => !(isUnitLikeType (t) && contains(switchTypes, getRegularTypeOfLiteralType(extractUnitType(t) ))));
23162
23178
return caseType.flags & TypeFlags.Never ? defaultType : getUnionType([caseType, defaultType]);
23163
23179
}
23164
23180
0 commit comments