diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cd4eeed7522..8fa124868cc 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11127,7 +11127,7 @@ namespace ts { * property is computed by inferring from the source property type to X for the type * variable T[P] (i.e. we treat the type T[P] as the type variable we're inferring for). */ - function inferTypeForHomomorphicMappedType(source: Type, target: MappedType): Type { + function inferTypeForHomomorphicMappedType(source: Type, target: MappedType, mappedTypeStack: [Type, Symbol][]): Type { const properties = getPropertiesOfType(source); let indexInfo = getIndexInfoOfType(source, IndexKind.String); if (properties.length === 0 && !indexInfo) { @@ -11160,7 +11160,7 @@ namespace ts { function inferTargetType(sourceType: Type): Type { inference.candidates = undefined; - inferTypes(inferences, sourceType, templateType); + inferTypes(inferences, sourceType, templateType, 0, mappedTypeStack); return inference.candidates ? getUnionType(inference.candidates, /*subtypeReduction*/ true) : emptyObjectType; } } @@ -11178,7 +11178,7 @@ namespace ts { return undefined; } - function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority: InferencePriority = 0) { + function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority: InferencePriority = 0, mappedTypeStack?: [Type, Symbol][]) { let symbolStack: Symbol[]; let visited: Map; inferFromTypes(originalSource, originalTarget); @@ -11395,7 +11395,12 @@ namespace ts { // such that direct inferences to T get priority over inferences to Partial, for example. const inference = getInferenceInfoForType((constraintType).type); if (inference && !inference.isFixed) { - const inferredType = inferTypeForHomomorphicMappedType(source, target); + if (contains(mappedTypeStack, [source, target.symbol], ([s1,t1],[s2,t2]) => s1 === s2 && t1 === t2)) { + return; + } + (mappedTypeStack || (mappedTypeStack = [])).push([source, target.symbol]); + const inferredType = inferTypeForHomomorphicMappedType(source, target, mappedTypeStack); + mappedTypeStack.pop(); if (inferredType) { const savePriority = priority; priority |= InferencePriority.MappedType;