@@ -2583,10 +2583,8 @@ namespace ts {
2583
2583
}
2584
2584
2585
2585
function createTypeNodeFromObjectType(type: ObjectType): TypeNode {
2586
- if (type.objectFlags & ObjectFlags.Mapped) {
2587
- if (getConstraintTypeFromMappedType(<MappedType>type).flags & (TypeFlags.TypeParameter | TypeFlags.Index)) {
2588
- return createMappedTypeNodeFromType(<MappedType>type);
2589
- }
2586
+ if (isGenericMappedType(type)) {
2587
+ return createMappedTypeNodeFromType(<MappedType>type);
2590
2588
}
2591
2589
2592
2590
const resolved = resolveStructuredTypeMembers(type);
@@ -3489,11 +3487,9 @@ namespace ts {
3489
3487
}
3490
3488
3491
3489
function writeLiteralType(type: ObjectType, flags: TypeFormatFlags) {
3492
- if (type.objectFlags & ObjectFlags.Mapped) {
3493
- if (getConstraintTypeFromMappedType(<MappedType>type).flags & (TypeFlags.TypeParameter | TypeFlags.Index)) {
3494
- writeMappedType(<MappedType>type);
3495
- return;
3496
- }
3490
+ if (isGenericMappedType(type)) {
3491
+ writeMappedType(<MappedType>type);
3492
+ return;
3497
3493
}
3498
3494
3499
3495
const resolved = resolveStructuredTypeMembers(type);
@@ -5792,8 +5788,7 @@ namespace ts {
5792
5788
}
5793
5789
5794
5790
function isGenericMappedType(type: Type) {
5795
- return getObjectFlags(type) & ObjectFlags.Mapped &&
5796
- maybeTypeOfKind(getConstraintTypeFromMappedType(<MappedType>type), TypeFlags.TypeVariable | TypeFlags.Index);
5791
+ return getObjectFlags(type) & ObjectFlags.Mapped && isGenericIndexType(getConstraintTypeFromMappedType(<MappedType>type));
5797
5792
}
5798
5793
5799
5794
function resolveStructuredTypeMembers(type: StructuredType): ResolvedType {
@@ -7602,26 +7597,36 @@ namespace ts {
7602
7597
return instantiateType(getTemplateTypeFromMappedType(type), templateMapper);
7603
7598
}
7604
7599
7600
+ function isGenericObjectType(type: Type): boolean {
7601
+ return type.flags & TypeFlags.TypeVariable ? true :
7602
+ getObjectFlags(type) & ObjectFlags.Mapped ? isGenericIndexType(getConstraintTypeFromMappedType(<MappedType>type)) :
7603
+ type.flags & TypeFlags.UnionOrIntersection ? forEach((<UnionOrIntersectionType>type).types, isGenericObjectType) :
7604
+ false;
7605
+ }
7606
+
7607
+ function isGenericIndexType(type: Type): boolean {
7608
+ return type.flags & (TypeFlags.TypeVariable | TypeFlags.Index) ? true :
7609
+ type.flags & TypeFlags.UnionOrIntersection ? forEach((<UnionOrIntersectionType>type).types, isGenericIndexType) :
7610
+ false;
7611
+ }
7612
+
7605
7613
function getIndexedAccessType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode) {
7606
- // If the index type is generic, if the object type is generic and doesn't originate in an expression,
7607
- // or if the object type is a mapped type with a generic constraint, we are performing a higher-order
7608
- // index access where we cannot meaningfully access the properties of the object type. Note that for a
7609
- // generic T and a non-generic K, we eagerly resolve T[K] if it originates in an expression. This is to
7610
- // preserve backwards compatibility. For example, an element access 'this["foo"]' has always been resolved
7611
- // eagerly using the constraint type of 'this' at the given location.
7612
- if (maybeTypeOfKind(indexType, TypeFlags.TypeVariable | TypeFlags.Index) ||
7613
- maybeTypeOfKind(objectType, TypeFlags.TypeVariable) && !(accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression) ||
7614
- isGenericMappedType(objectType)) {
7614
+ // If the object type is a mapped type { [P in K]: E }, where K is generic, we instantiate E using a mapper
7615
+ // that substitutes the index type for P. For example, for an index access { [P in K]: Box<T[P]> }[X], we
7616
+ // construct the type Box<T[X]>.
7617
+ if (isGenericMappedType(objectType)) {
7618
+ return getIndexedAccessForMappedType(<MappedType>objectType, indexType, accessNode);
7619
+ }
7620
+ // Otherwise, if the index type is generic, or if the object type is generic and doesn't originate in an
7621
+ // expression, we are performing a higher-order index access where we cannot meaningfully access the properties
7622
+ // of the object type. Note that for a generic T and a non-generic K, we eagerly resolve T[K] if it originates
7623
+ // in an expression. This is to preserve backwards compatibility. For example, an element access 'this["foo"]'
7624
+ // has always been resolved eagerly using the constraint type of 'this' at the given location.
7625
+ if (isGenericIndexType(indexType) || !(accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression) && isGenericObjectType(objectType)) {
7615
7626
if (objectType.flags & TypeFlags.Any) {
7616
7627
return objectType;
7617
7628
}
7618
- // If the object type is a mapped type { [P in K]: E }, we instantiate E using a mapper that substitutes
7619
- // the index type for P. For example, for an index access { [P in K]: Box<T[P]> }[X], we construct the
7620
- // type Box<T[X]>.
7621
- if (isGenericMappedType(objectType)) {
7622
- return getIndexedAccessForMappedType(<MappedType>objectType, indexType, accessNode);
7623
- }
7624
- // Otherwise we defer the operation by creating an indexed access type.
7629
+ // Defer the operation by creating an indexed access type.
7625
7630
const id = objectType.id + "," + indexType.id;
7626
7631
let type = indexedAccessTypes.get(id);
7627
7632
if (!type) {
0 commit comments