@@ -2193,6 +2193,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2193
2193
/** Key is "/path/to/a.ts|/path/to/b.ts". */
2194
2194
var amalgamatedDuplicates: Map<string, DuplicateInfoForFiles> | undefined;
2195
2195
var reverseMappedCache = new Map<string, Type | undefined>();
2196
+ var reverseHomomorphicMappedCache = new Map<string, Type | undefined>();
2196
2197
var ambientModulesCache: Symbol[] | undefined;
2197
2198
/**
2198
2199
* List of every ambient module with a "*" wildcard.
@@ -7003,20 +7004,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
7003
7004
}
7004
7005
7005
7006
function shouldUsePlaceholderForProperty(propertySymbol: Symbol, context: NodeBuilderContext) {
7006
- // Use placeholders for reverse mapped types we've either already descended into, or which
7007
- // are nested reverse mappings within a mapping over a non-anonymous type. The later is a restriction mostly just to
7007
+ // Use placeholders for reverse mapped types we've either
7008
+ // (1) already descended into, or
7009
+ // (2) are nested reverse mappings within a mapping over a non-anonymous type, or
7010
+ // (3) are deeply nested properties that originate from the same mapped type.
7011
+ // Condition (2) is a restriction mostly just to
7008
7012
// reduce the blowup in printback size from doing, eg, a deep reverse mapping over `Window`.
7009
7013
// Since anonymous types usually come from expressions, this allows us to preserve the output
7010
7014
// for deep mappings which likely come from expressions, while truncating those parts which
7011
7015
// come from mappings over library functions.
7016
+ // Condition (3) limits printing of possibly infinitely deep reverse mapped types.
7017
+ const depth = 3;
7012
7018
return !!(getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped)
7013
7019
&& (
7014
7020
contains(context.reverseMappedStack, propertySymbol as ReverseMappedSymbol)
7015
7021
|| (
7016
7022
context.reverseMappedStack?.[0]
7017
7023
&& !(getObjectFlags(last(context.reverseMappedStack).links.propertyType) & ObjectFlags.Anonymous)
7018
7024
)
7025
+ || isDeeplyNestedReverseMappedTypeProperty()
7019
7026
);
7027
+ function isDeeplyNestedReverseMappedTypeProperty() {
7028
+ if ((context.reverseMappedStack?.length ?? 0) < depth) {
7029
+ return false;
7030
+ }
7031
+ for (let i = 0; i < depth; i++) {
7032
+ const prop = context.reverseMappedStack![context.reverseMappedStack!.length - 1 - i];
7033
+ if (prop.links.mappedType.symbol !== (propertySymbol as ReverseMappedSymbol).links.mappedType.symbol) {
7034
+ return false;
7035
+ }
7036
+ }
7037
+ return true;
7038
+ }
7020
7039
}
7021
7040
7022
7041
function addPropertyToElementList(propertySymbol: Symbol, context: NodeBuilderContext, typeElements: TypeElement[]) {
@@ -25604,11 +25623,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
25604
25623
*/
25605
25624
function inferTypeForHomomorphicMappedType(source: Type, target: MappedType, constraint: IndexType): Type | undefined {
25606
25625
const cacheKey = source.id + "," + target.id + "," + constraint.id;
25607
- if (reverseMappedCache .has(cacheKey)) {
25608
- return reverseMappedCache .get(cacheKey);
25626
+ if (reverseHomomorphicMappedCache .has(cacheKey)) {
25627
+ return reverseHomomorphicMappedCache .get(cacheKey);
25609
25628
}
25610
25629
const type = createReverseMappedType(source, target, constraint);
25611
- reverseMappedCache .set(cacheKey, type);
25630
+ reverseHomomorphicMappedCache .set(cacheKey, type);
25612
25631
return type;
25613
25632
}
25614
25633
0 commit comments