@@ -19191,11 +19191,15 @@ namespace ts {
19191
19191
// parameter 'T extends 1 | 2', the intersection 'T & 1' should be reduced to '1' such that it doesn't
19192
19192
// appear to be comparable to '2'.
19193
19193
if (relation === comparableRelation && target.flags & TypeFlags.Primitive) {
19194
- const constraints = sameMap((source as IntersectionType).types, getBaseConstraintOrType );
19194
+ const constraints = sameMap((source as IntersectionType).types, t => t.flags & TypeFlags.Instantiable ? getBaseConstraintOfType(t) || unknownType : t );
19195
19195
if (constraints !== (source as IntersectionType).types) {
19196
19196
source = getIntersectionType(constraints);
19197
+ if (source.flags & TypeFlags.Never) {
19198
+ return Ternary.False;
19199
+ }
19197
19200
if (!(source.flags & TypeFlags.Intersection)) {
19198
- return isRelatedTo(source, target, RecursionFlags.Source, /*reportErrors*/ false);
19201
+ return isRelatedTo(source, target, RecursionFlags.Source, /*reportErrors*/ false) ||
19202
+ isRelatedTo(target, source, RecursionFlags.Source, /*reportErrors*/ false);
19199
19203
}
19200
19204
}
19201
19205
}
@@ -19516,7 +19520,7 @@ namespace ts {
19516
19520
// the type param can be compared with itself in the target (with the influence of its constraint to match other parts)
19517
19521
// For example, if `T extends 1 | 2` and `U extends 2 | 3` and we compare `T & U` to `T & U & (1 | 2 | 3)`
19518
19522
const constraint = getEffectiveConstraintOfIntersection(source.flags & TypeFlags.Intersection ? (source as IntersectionType).types: [source], !!(target.flags & TypeFlags.Union));
19519
- if (constraint && everyType(constraint, c => c !== source)) { // Skip comparison if expansion contains the source itself
19523
+ if (constraint && !(constraint.flags & TypeFlags.Never) && everyType(constraint, c => c !== source)) { // Skip comparison if expansion contains the source itself
19520
19524
// TODO: Stack errors so we get a pyramid for the "normal" comparison above, _and_ a second for this
19521
19525
result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState);
19522
19526
}
@@ -25294,25 +25298,11 @@ namespace ts {
25294
25298
assumeTrue = !assumeTrue;
25295
25299
}
25296
25300
const valueType = getTypeOfExpression(value);
25297
- if (((type.flags & TypeFlags.Unknown) || isEmptyAnonymousObjectType(type) && !(valueType.flags & TypeFlags.Nullable)) &&
25298
- assumeTrue &&
25299
- (operator === SyntaxKind.EqualsEqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken)
25300
- ) {
25301
- if (valueType.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive)) {
25302
- return valueType;
25303
- }
25304
- if (valueType.flags & TypeFlags.Object) {
25305
- return nonPrimitiveType;
25306
- }
25307
- if (type.flags & TypeFlags.Unknown) {
25308
- return type;
25309
- }
25310
- }
25301
+ const doubleEquals = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken;
25311
25302
if (valueType.flags & TypeFlags.Nullable) {
25312
25303
if (!strictNullChecks) {
25313
25304
return type;
25314
25305
}
25315
- const doubleEquals = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken;
25316
25306
const facts = doubleEquals ?
25317
25307
assumeTrue ? TypeFacts.EQUndefinedOrNull : TypeFacts.NEUndefinedOrNull :
25318
25308
valueType.flags & TypeFlags.Null ?
@@ -25321,10 +25311,16 @@ namespace ts {
25321
25311
return getAdjustedTypeWithFacts(type, facts);
25322
25312
}
25323
25313
if (assumeTrue) {
25324
- const filterFn: (t: Type) => boolean = operator === SyntaxKind.EqualsEqualsToken ?
25325
- t => areTypesComparable(t, valueType) || isCoercibleUnderDoubleEquals(t, valueType) :
25326
- t => areTypesComparable(t, valueType);
25327
- return replacePrimitivesWithLiterals(filterType(type, filterFn), valueType);
25314
+ if (!doubleEquals && (type.flags & TypeFlags.Unknown || someType(type, isEmptyAnonymousObjectType))) {
25315
+ if (valueType.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive) || isEmptyAnonymousObjectType(valueType)) {
25316
+ return valueType;
25317
+ }
25318
+ if (valueType.flags & TypeFlags.Object) {
25319
+ return nonPrimitiveType;
25320
+ }
25321
+ }
25322
+ const filteredType = filterType(type, t => areTypesComparable(t, valueType) || doubleEquals && isCoercibleUnderDoubleEquals(t, valueType));
25323
+ return replacePrimitivesWithLiterals(filteredType, valueType);
25328
25324
}
25329
25325
if (isUnitType(valueType)) {
25330
25326
return filterType(type, t => !(isUnitLikeType(t) && areTypesComparable(t, valueType)));
0 commit comments