@@ -196,6 +196,7 @@ namespace ts {
196
196
Source = 1 << 0,
197
197
Target = 1 << 1,
198
198
PropertyCheck = 1 << 2,
199
+ InPropertyCheck = 1 << 3,
199
200
}
200
201
201
202
const enum MappedTypeModifiers {
@@ -15245,6 +15246,7 @@ namespace ts {
15245
15246
let overrideNextErrorInfo = 0; // How many `reportRelationError` calls should be skipped in the elaboration pyramid
15246
15247
let lastSkippedInfo: [Type, Type] | undefined;
15247
15248
let incompatibleStack: [DiagnosticMessage, (string | number)?, (string | number)?, (string | number)?, (string | number)?][] = [];
15249
+ let inPropertyCheck = false;
15248
15250
15249
15251
Debug.assert(relation !== identityRelation || !errorNode, "no error reporting in identity checking");
15250
15252
@@ -15680,10 +15682,15 @@ namespace ts {
15680
15682
// function foo<T extends object>(x: { a?: string }, y: T & { a: boolean }) {
15681
15683
// x = y; // Mismatched property in source intersection
15682
15684
// }
15683
- if (result && (
15685
+ //
15686
+ // We suppress recursive intersection property checks because they can generate lots of work when relating
15687
+ // recursive intersections that are structurally similar but not exactly identical. See #37854.
15688
+ if (result && !inPropertyCheck && (
15684
15689
target.flags & TypeFlags.Intersection && (isPerformingExcessPropertyChecks || isPerformingCommonPropertyChecks) ||
15685
15690
isNonGenericObjectType(target) && source.flags & TypeFlags.Intersection && getApparentType(source).flags & TypeFlags.StructuredType && !some((<IntersectionType>source).types, t => !!(getObjectFlags(t) & ObjectFlags.NonInferrableType)))) {
15691
+ inPropertyCheck = true;
15686
15692
result &= recursiveTypeRelatedTo(source, target, reportErrors, IntersectionState.PropertyCheck);
15693
+ inPropertyCheck = false;
15687
15694
}
15688
15695
15689
15696
if (!result && reportErrors) {
@@ -15980,7 +15987,7 @@ namespace ts {
15980
15987
if (overflow) {
15981
15988
return Ternary.False;
15982
15989
}
15983
- const id = getRelationKey(source, target, intersectionState, relation);
15990
+ const id = getRelationKey(source, target, intersectionState | (inPropertyCheck ? IntersectionState.InPropertyCheck : 0) , relation);
15984
15991
const entry = relation.get(id);
15985
15992
if (entry !== undefined) {
15986
15993
if (reportErrors && entry & RelationComparisonResult.Failed && !(entry & RelationComparisonResult.Reported)) {
0 commit comments