@@ -19216,11 +19216,15 @@ namespace ts {
19216
19216
// parameter 'T extends 1 | 2', the intersection 'T & 1' should be reduced to '1' such that it doesn't
19217
19217
// appear to be comparable to '2'.
19218
19218
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 );
19220
19220
if (constraints !== (source as IntersectionType).types) {
19221
19221
source = getIntersectionType(constraints);
19222
+ if (source.flags & TypeFlags.Never) {
19223
+ return Ternary.False;
19224
+ }
19222
19225
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);
19224
19228
}
19225
19229
}
19226
19230
}
@@ -19541,7 +19545,7 @@ namespace ts {
19541
19545
// the type param can be compared with itself in the target (with the influence of its constraint to match other parts)
19542
19546
// For example, if `T extends 1 | 2` and `U extends 2 | 3` and we compare `T & U` to `T & U & (1 | 2 | 3)`
19543
19547
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
19545
19549
// TODO: Stack errors so we get a pyramid for the "normal" comparison above, _and_ a second for this
19546
19550
result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState);
19547
19551
}
@@ -25322,25 +25326,11 @@ namespace ts {
25322
25326
assumeTrue = !assumeTrue;
25323
25327
}
25324
25328
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;
25339
25330
if (valueType.flags & TypeFlags.Nullable) {
25340
25331
if (!strictNullChecks) {
25341
25332
return type;
25342
25333
}
25343
- const doubleEquals = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken;
25344
25334
const facts = doubleEquals ?
25345
25335
assumeTrue ? TypeFacts.EQUndefinedOrNull : TypeFacts.NEUndefinedOrNull :
25346
25336
valueType.flags & TypeFlags.Null ?
@@ -25349,10 +25339,16 @@ namespace ts {
25349
25339
return getAdjustedTypeWithFacts(type, facts);
25350
25340
}
25351
25341
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);
25356
25352
}
25357
25353
if (isUnitType(valueType)) {
25358
25354
return filterType(type, t => !(isUnitLikeType(t) && areTypesComparable(t, valueType)));
0 commit comments