@@ -2194,6 +2194,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2194
2194
/** Key is "/path/to/a.ts|/path/to/b.ts". */
2195
2195
var amalgamatedDuplicates: Map<string, DuplicateInfoForFiles> | undefined;
2196
2196
var reverseMappedCache = new Map<string, Type | undefined>();
2197
+ var reverseHomomorphicMappedCache = new Map<string, Type | undefined>();
2197
2198
var ambientModulesCache: Symbol[] | undefined;
2198
2199
/**
2199
2200
* List of every ambient module with a "*" wildcard.
@@ -7030,20 +7031,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
7030
7031
}
7031
7032
7032
7033
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
7035
7039
// reduce the blowup in printback size from doing, eg, a deep reverse mapping over `Window`.
7036
7040
// Since anonymous types usually come from expressions, this allows us to preserve the output
7037
7041
// for deep mappings which likely come from expressions, while truncating those parts which
7038
7042
// come from mappings over library functions.
7043
+ // Condition (3) limits printing of possibly infinitely deep reverse mapped types.
7044
+ const depth = 3;
7039
7045
return !!(getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped)
7040
7046
&& (
7041
7047
contains(context.reverseMappedStack, propertySymbol as ReverseMappedSymbol)
7042
7048
|| (
7043
7049
context.reverseMappedStack?.[0]
7044
7050
&& !(getObjectFlags(last(context.reverseMappedStack).links.propertyType) & ObjectFlags.Anonymous)
7045
7051
)
7052
+ || isDeeplyNestedReverseMappedTypeProperty()
7046
7053
);
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
+ }
7047
7066
}
7048
7067
7049
7068
function addPropertyToElementList(propertySymbol: Symbol, context: NodeBuilderContext, typeElements: TypeElement[]) {
@@ -25657,11 +25676,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
25657
25676
*/
25658
25677
function inferTypeForHomomorphicMappedType(source: Type, target: MappedType, constraint: IndexType): Type | undefined {
25659
25678
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);
25662
25681
}
25663
25682
const type = createReverseMappedType(source, target, constraint);
25664
- reverseMappedCache .set(cacheKey, type);
25683
+ reverseHomomorphicMappedCache .set(cacheKey, type);
25665
25684
return type;
25666
25685
}
25667
25686
0 commit comments