@@ -335,6 +335,7 @@ namespace ts {
335335
336336 const globals = createSymbolTable();
337337 const deferredInferenceCache = createMap<Type | undefined>();
338+ const deferredMappedTypeInstantiationStack: string[] = [];
338339 let ambientModulesCache: Symbol[] | undefined;
339340 /**
340341 * List of every ambient module with a "*" wildcard.
@@ -2867,7 +2868,23 @@ namespace ts {
28672868 }
28682869
28692870 for (const propertySymbol of properties) {
2870- const propertyType = getTypeOfSymbol(propertySymbol);
2871+ let propertyType: Type;
2872+ if (getCheckFlags(propertySymbol) & CheckFlags.DeferredInferred) {
2873+ const deferred = propertySymbol as DeferredTransientSymbol;
2874+ const key = deferred.propertyType.id + "," + (deferred.mappedType.symbol ? deferred.mappedType.symbol.id : "");
2875+ // Temporary solution to recursive printing: zero out repeated types.
2876+ if (contains(deferredMappedTypeInstantiationStack, key)) {
2877+ // TODO: Could probably be an actual cache that returns {} when it contains undefined.
2878+ propertyType = emptyObjectType;
2879+ }
2880+ else {
2881+ deferredMappedTypeInstantiationStack.push(key)
2882+ propertyType = getTypeOfSymbol(propertySymbol);
2883+ }
2884+ }
2885+ else {
2886+ propertyType = getTypeOfSymbol(propertySymbol);
2887+ }
28712888 const saveEnclosingDeclaration = context.enclosingDeclaration;
28722889 context.enclosingDeclaration = undefined;
28732890 const propertyName = symbolToName(propertySymbol, context, SymbolFlags.Value, /*expectsIdentifier*/ true);
@@ -2894,6 +2911,9 @@ namespace ts {
28942911 /*initializer*/ undefined);
28952912 typeElements.push(propertySignature);
28962913 }
2914+ if (getCheckFlags(propertySymbol) & CheckFlags.DeferredInferred) {
2915+ deferredMappedTypeInstantiationStack.pop();
2916+ }
28972917 }
28982918 return typeElements.length ? typeElements : undefined;
28992919 }
@@ -4869,7 +4889,7 @@ namespace ts {
48694889 return getTypeOfInstantiatedSymbol(symbol);
48704890 }
48714891 if (getCheckFlags(symbol) & CheckFlags.DeferredInferred) {
4872- return inferTargetType ((symbol as DeferredTransientSymbol).propertyType, (symbol as DeferredTransientSymbol).mappedType);
4892+ return inferDeferredMappedType ((symbol as DeferredTransientSymbol).propertyType, (symbol as DeferredTransientSymbol).mappedType);
48734893 }
48744894 if (symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property)) {
48754895 return getTypeOfVariableOrParameterOrProperty(symbol);
@@ -11233,7 +11253,13 @@ namespace ts {
1123311253 if (deferredInferenceCache.has(key)) {
1123411254 return deferredInferenceCache.get(key);
1123511255 }
11236- deferredInferenceCache.set(key, function() {
11256+ deferredInferenceCache.set(key, undefined);
11257+ const type = createDeferredMappedType(source, target);
11258+ deferredInferenceCache.set(key, type);
11259+ return type;
11260+ }
11261+
11262+ function createDeferredMappedType(source: Type, target: MappedType) {
1123711263 const properties = getPropertiesOfType(source);
1123811264 let indexInfo = getIndexInfoOfType(source, IndexKind.String);
1123911265 if (properties.length === 0 && !indexInfo) {
@@ -11257,14 +11283,15 @@ namespace ts {
1125711283 members.set(prop.escapedName, inferredProp);
1125811284 }
1125911285 if (indexInfo) {
11260- // TODO: Defer this too. BARREL OF LAUGHS RIGHT THERE
11261- indexInfo = createIndexInfo(inferTargetType(indexInfo.type, target), readonlyMask && indexInfo.isReadonly);
11286+ // TODO: Defer this too.
11287+ // (probably the simplest way is to have a special type that defers the creation of (at least) its index info in
11288+ // resolveStructuredTypeMembers
11289+ indexInfo = createIndexInfo(inferDeferredMappedType(indexInfo.type, target), readonlyMask && indexInfo.isReadonly);
1126211290 }
1126311291 return createAnonymousType(undefined, members, emptyArray, emptyArray, indexInfo, undefined);
11264- }());
1126511292 }
1126611293
11267- function inferTargetType (sourceType: Type, target: MappedType): Type {
11294+ function inferDeferredMappedType (sourceType: Type, target: MappedType): Type {
1126811295 const typeParameter = <TypeParameter>getIndexedAccessType((<IndexType>getConstraintTypeFromMappedType(target)).type, getTypeParameterFromMappedType(target));
1126911296 const templateType = getTemplateTypeFromMappedType(target);
1127011297 const inference = createInferenceInfo(typeParameter);
0 commit comments