@@ -2194,6 +2194,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
21942194 /** Key is "/path/to/a.ts|/path/to/b.ts". */
21952195 var amalgamatedDuplicates: Map<string, DuplicateInfoForFiles> | undefined;
21962196 var reverseMappedCache = new Map<string, Type | undefined>();
2197+ var reverseHomomorphicMappedCache = new Map<string, Type | undefined>();
21972198 var ambientModulesCache: Symbol[] | undefined;
21982199 /**
21992200 * List of every ambient module with a "*" wildcard.
@@ -7030,20 +7031,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
70307031 }
70317032
70327033 function shouldUsePlaceholderForProperty(propertySymbol: Symbol, context: NodeBuilderContext) {
7033- // Use placeholders for reverse mapped types we've either already descended into, or which
7034- // are nested reverse mappings within a mapping over a non-anonymous type. The later is a restriction mostly just to
7034+ // Use placeholders for reverse mapped types we've either
7035+ // (1) already descended into, or
7036+ // (2) are nested reverse mappings within a mapping over a non-anonymous type, or
7037+ // (3) are deeply nested properties that originate from the same mapped type.
7038+ // Condition (2) is a restriction mostly just to
70357039 // reduce the blowup in printback size from doing, eg, a deep reverse mapping over `Window`.
70367040 // Since anonymous types usually come from expressions, this allows us to preserve the output
70377041 // for deep mappings which likely come from expressions, while truncating those parts which
70387042 // come from mappings over library functions.
7043+ // Condition (3) limits printing of possibly infinitely deep reverse mapped types.
7044+ const depth = 3;
70397045 return !!(getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped)
70407046 && (
70417047 contains(context.reverseMappedStack, propertySymbol as ReverseMappedSymbol)
70427048 || (
70437049 context.reverseMappedStack?.[0]
70447050 && !(getObjectFlags(last(context.reverseMappedStack).links.propertyType) & ObjectFlags.Anonymous)
70457051 )
7052+ || isDeeplyNestedReverseMappedTypeProperty()
70467053 );
7054+ function isDeeplyNestedReverseMappedTypeProperty() {
7055+ if ((context.reverseMappedStack?.length ?? 0) < depth) {
7056+ return false;
7057+ }
7058+ for (let i = 0; i < depth; i++) {
7059+ const prop = context.reverseMappedStack![context.reverseMappedStack!.length - 1 - i];
7060+ if (prop.links.mappedType.symbol !== (propertySymbol as ReverseMappedSymbol).links.mappedType.symbol) {
7061+ return false;
7062+ }
7063+ }
7064+ return true;
7065+ }
70477066 }
70487067
70497068 function addPropertyToElementList(propertySymbol: Symbol, context: NodeBuilderContext, typeElements: TypeElement[]) {
@@ -25657,11 +25676,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2565725676 */
2565825677 function inferTypeForHomomorphicMappedType(source: Type, target: MappedType, constraint: IndexType): Type | undefined {
2565925678 const cacheKey = source.id + "," + target.id + "," + constraint.id;
25660- if (reverseMappedCache .has(cacheKey)) {
25661- return reverseMappedCache .get(cacheKey);
25679+ if (reverseHomomorphicMappedCache .has(cacheKey)) {
25680+ return reverseHomomorphicMappedCache .get(cacheKey);
2566225681 }
2566325682 const type = createReverseMappedType(source, target, constraint);
25664- reverseMappedCache .set(cacheKey, type);
25683+ reverseHomomorphicMappedCache .set(cacheKey, type);
2566525684 return type;
2566625685 }
2566725686
0 commit comments