Skip to content

Commit 0b23811

Browse files
committed
Handle indexed mapped types in transformIndexedAccessType
Also rename transformIndexedAccessType to simplifyIndexedAccessType
1 parent 7dbea0e commit 0b23811

1 file changed

Lines changed: 22 additions & 11 deletions

File tree

src/compiler/checker.ts

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)