@@ -19216,11 +19216,15 @@ namespace ts {
1921619216                // parameter 'T extends 1 | 2', the intersection 'T & 1' should be reduced to '1' such that it doesn't
1921719217                // appear to be comparable to '2'.
1921819218                if (relation === comparableRelation && target.flags & TypeFlags.Primitive) {
19219-                     const constraints = sameMap((source as IntersectionType).types, getBaseConstraintOrType );
19219+                     const constraints = sameMap((source as IntersectionType).types, t => t.flags & TypeFlags.Instantiable ? getBaseConstraintOfType(t) || unknownType : t );
1922019220                    if (constraints !== (source as IntersectionType).types) {
1922119221                        source = getIntersectionType(constraints);
19222+                         if (source.flags & TypeFlags.Never) {
19223+                             return Ternary.False;
19224+                         }
1922219225                        if (!(source.flags & TypeFlags.Intersection)) {
19223-                             return isRelatedTo(source, target, RecursionFlags.Source, /*reportErrors*/ false);
19226+                             return isRelatedTo(source, target, RecursionFlags.Source, /*reportErrors*/ false) ||
19227+                                 isRelatedTo(target, source, RecursionFlags.Source, /*reportErrors*/ false);
1922419228                        }
1922519229                    }
1922619230                }
@@ -19541,7 +19545,7 @@ namespace ts {
1954119545                    // the type param can be compared with itself in the target (with the influence of its constraint to match other parts)
1954219546                    // For example, if `T extends 1 | 2` and `U extends 2 | 3` and we compare `T & U` to `T & U & (1 | 2 | 3)`
1954319547                    const constraint = getEffectiveConstraintOfIntersection(source.flags & TypeFlags.Intersection ? (source as IntersectionType).types: [source], !!(target.flags & TypeFlags.Union));
19544-                     if (constraint && everyType(constraint, c => c !== source)) { // Skip comparison if expansion contains the source itself
19548+                     if (constraint && !(constraint.flags & TypeFlags.Never) &&  everyType(constraint, c => c !== source)) { // Skip comparison if expansion contains the source itself
1954519549                        // TODO: Stack errors so we get a pyramid for the "normal" comparison above, _and_ a second for this
1954619550                        result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState);
1954719551                    }
@@ -25322,25 +25326,11 @@ namespace ts {
2532225326                    assumeTrue = !assumeTrue;
2532325327                }
2532425328                const valueType = getTypeOfExpression(value);
25325-                 if (((type.flags & TypeFlags.Unknown) || isEmptyAnonymousObjectType(type) && !(valueType.flags & TypeFlags.Nullable)) &&
25326-                     assumeTrue &&
25327-                     (operator === SyntaxKind.EqualsEqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken)
25328-                 ) {
25329-                     if (valueType.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive)) {
25330-                         return valueType;
25331-                     }
25332-                     if (valueType.flags & TypeFlags.Object) {
25333-                         return nonPrimitiveType;
25334-                     }
25335-                     if (type.flags & TypeFlags.Unknown) {
25336-                         return type;
25337-                     }
25338-                 }
25329+                 const doubleEquals = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken;
2533925330                if (valueType.flags & TypeFlags.Nullable) {
2534025331                    if (!strictNullChecks) {
2534125332                        return type;
2534225333                    }
25343-                     const doubleEquals = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken;
2534425334                    const facts = doubleEquals ?
2534525335                        assumeTrue ? TypeFacts.EQUndefinedOrNull : TypeFacts.NEUndefinedOrNull :
2534625336                        valueType.flags & TypeFlags.Null ?
@@ -25349,10 +25339,16 @@ namespace ts {
2534925339                    return getAdjustedTypeWithFacts(type, facts);
2535025340                }
2535125341                if (assumeTrue) {
25352-                     const filterFn: (t: Type) => boolean = operator === SyntaxKind.EqualsEqualsToken ?
25353-                         t => areTypesComparable(t, valueType) || isCoercibleUnderDoubleEquals(t, valueType) :
25354-                         t => areTypesComparable(t, valueType);
25355-                     return replacePrimitivesWithLiterals(filterType(type, filterFn), valueType);
25342+                     if (!doubleEquals && (type.flags & TypeFlags.Unknown || someType(type, isEmptyAnonymousObjectType))) {
25343+                         if (valueType.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive) || isEmptyAnonymousObjectType(valueType)) {
25344+                             return valueType;
25345+                         }
25346+                         if (valueType.flags & TypeFlags.Object) {
25347+                             return nonPrimitiveType;
25348+                         }
25349+                     }
25350+                     const filteredType = filterType(type, t => areTypesComparable(t, valueType) || doubleEquals && isCoercibleUnderDoubleEquals(t, valueType));
25351+                     return replacePrimitivesWithLiterals(filteredType, valueType);
2535625352                }
2535725353                if (isUnitType(valueType)) {
2535825354                    return filterType(type, t => !(isUnitLikeType(t) && areTypesComparable(t, valueType)));
0 commit comments