@@ -6351,7 +6351,7 @@ namespace ts {
63516351 return getObjectFlags(type) & ObjectFlags.Mapped && !!(<MappedType>type).declaration.questionToken;
63526352 }
63536353
6354- function isGenericMappedType(type: Type) {
6354+ function isGenericMappedType(type: Type): type is MappedType {
63556355 return getObjectFlags(type) & ObjectFlags.Mapped && isGenericIndexType(getConstraintTypeFromMappedType(<MappedType>type));
63566356 }
63576357
@@ -6463,14 +6463,12 @@ namespace ts {
64636463 }
64646464
64656465 function getConstraintOfIndexedAccess(type: IndexedAccessType) {
6466- const transformed = getTransformedIndexedAccessType (type);
6466+ const transformed = simplifyIndexedAccessType (type);
64676467 if (transformed) {
64686468 return transformed;
64696469 }
64706470 const baseObjectType = getBaseConstraintOfType(type.objectType);
6471- const keepTypeParameterForMappedType = baseObjectType && getObjectFlags(baseObjectType) & ObjectFlags.Mapped &&
6472- type.indexType.flags & TypeFlags.TypeParameter;
6473- const baseIndexType = !keepTypeParameterForMappedType && getBaseConstraintOfType(type.indexType);
6471+ const baseIndexType = getBaseConstraintOfType(type.indexType);
64746472 if (baseIndexType === stringType && !getIndexInfoOfType(baseObjectType || type.objectType, IndexKind.String)) {
64756473 // getIndexedAccessType returns `any` for X[string] where X doesn't have an index signature.
64766474 // to avoid this, return `undefined`.
@@ -6546,7 +6544,7 @@ namespace ts {
65466544 return stringType;
65476545 }
65486546 if (t.flags & TypeFlags.IndexedAccess) {
6549- const transformed = getTransformedIndexedAccessType (<IndexedAccessType>t);
6547+ const transformed = simplifyIndexedAccessType (<IndexedAccessType>t);
65506548 if (transformed) {
65516549 return getBaseConstraint(transformed);
65526550 }
@@ -6555,6 +6553,9 @@ namespace ts {
65556553 const baseIndexedAccess = baseObjectType && baseIndexType ? getIndexedAccessType(baseObjectType, baseIndexType) : undefined;
65566554 return baseIndexedAccess && baseIndexedAccess !== unknownType ? getBaseConstraint(baseIndexedAccess) : undefined;
65576555 }
6556+ if (isGenericMappedType(t)) {
6557+ return emptyObjectType;
6558+ }
65586559 return t;
65596560 }
65606561 }
@@ -8355,7 +8356,7 @@ namespace ts {
83558356
83568357 // Transform an indexed access to a simpler form, if possible. Return the simpler form, or return
83578358 // undefined if no transformation is possible.
8358- function getTransformedIndexedAccessType (type: IndexedAccessType): Type {
8359+ function simplifyIndexedAccessType (type: IndexedAccessType): Type {
83598360 const objectType = type.objectType;
83608361 // Given an indexed access type T[K], if T is an intersection containing one or more generic types and one or
83618362 // more object types with only a string index signature, e.g. '(U & V & { [x: string]: D })[K]', return a
@@ -8381,14 +8382,24 @@ namespace ts {
83818382 // that substitutes the index type for P. For example, for an index access { [P in K]: Box<T[P]> }[X], we
83828383 // construct the type Box<T[X]>.
83838384 if (isGenericMappedType(objectType)) {
8384- const mapper = createTypeMapper([getTypeParameterFromMappedType(<MappedType>objectType)], [type.indexType]);
8385- const objectTypeMapper = (<MappedType>objectType).mapper;
8386- const templateMapper = objectTypeMapper ? combineTypeMappers(objectTypeMapper, mapper) : mapper;
8387- return instantiateType(getTemplateTypeFromMappedType(<MappedType>objectType), templateMapper);
8385+ return substituteIndexedMappedType(objectType, type);
8386+ }
8387+ if (objectType.flags & TypeFlags.TypeParameter) {
8388+ const constraint = getConstraintFromTypeParameter(objectType as TypeParameter);
8389+ if (constraint && isGenericMappedType(constraint)) {
8390+ return substituteIndexedMappedType(constraint, type);
8391+ }
83888392 }
83898393 return undefined;
83908394 }
83918395
8396+ function substituteIndexedMappedType(objectType: MappedType, type: IndexedAccessType) {
8397+ const mapper = createTypeMapper([getTypeParameterFromMappedType(<MappedType>objectType)], [type.indexType]);
8398+ const objectTypeMapper = (<MappedType>objectType).mapper;
8399+ const templateMapper = objectTypeMapper ? combineTypeMappers(objectTypeMapper, mapper) : mapper;
8400+ return instantiateType(getTemplateTypeFromMappedType(<MappedType>objectType), templateMapper);
8401+ }
8402+
83928403 function getIndexedAccessType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode): Type {
83938404 // If the index type is generic, or if the object type is generic and doesn't originate in an expression,
83948405 // we are performing a higher-order index access where we cannot meaningfully access the properties of the
0 commit comments