Defer indexed access type resolution in more cases
This commit is contained in:
parent
f945b26b54
commit
5895057578
1 changed files with 32 additions and 27 deletions
|
@ -2583,10 +2583,8 @@ namespace ts {
|
||||||
}
|
}
|
||||||
|
|
||||||
function createTypeNodeFromObjectType(type: ObjectType): TypeNode {
|
function createTypeNodeFromObjectType(type: ObjectType): TypeNode {
|
||||||
if (type.objectFlags & ObjectFlags.Mapped) {
|
if (isGenericMappedType(type)) {
|
||||||
if (getConstraintTypeFromMappedType(<MappedType>type).flags & (TypeFlags.TypeParameter | TypeFlags.Index)) {
|
return createMappedTypeNodeFromType(<MappedType>type);
|
||||||
return createMappedTypeNodeFromType(<MappedType>type);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolved = resolveStructuredTypeMembers(type);
|
const resolved = resolveStructuredTypeMembers(type);
|
||||||
|
@ -3489,11 +3487,9 @@ namespace ts {
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeLiteralType(type: ObjectType, flags: TypeFormatFlags) {
|
function writeLiteralType(type: ObjectType, flags: TypeFormatFlags) {
|
||||||
if (type.objectFlags & ObjectFlags.Mapped) {
|
if (isGenericMappedType(type)) {
|
||||||
if (getConstraintTypeFromMappedType(<MappedType>type).flags & (TypeFlags.TypeParameter | TypeFlags.Index)) {
|
writeMappedType(<MappedType>type);
|
||||||
writeMappedType(<MappedType>type);
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolved = resolveStructuredTypeMembers(type);
|
const resolved = resolveStructuredTypeMembers(type);
|
||||||
|
@ -5792,8 +5788,7 @@ namespace ts {
|
||||||
}
|
}
|
||||||
|
|
||||||
function isGenericMappedType(type: Type) {
|
function isGenericMappedType(type: Type) {
|
||||||
return getObjectFlags(type) & ObjectFlags.Mapped &&
|
return getObjectFlags(type) & ObjectFlags.Mapped && isGenericIndexType(getConstraintTypeFromMappedType(<MappedType>type));
|
||||||
maybeTypeOfKind(getConstraintTypeFromMappedType(<MappedType>type), TypeFlags.TypeVariable | TypeFlags.Index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveStructuredTypeMembers(type: StructuredType): ResolvedType {
|
function resolveStructuredTypeMembers(type: StructuredType): ResolvedType {
|
||||||
|
@ -7602,26 +7597,36 @@ namespace ts {
|
||||||
return instantiateType(getTemplateTypeFromMappedType(type), templateMapper);
|
return instantiateType(getTemplateTypeFromMappedType(type), templateMapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isGenericObjectType(type: Type): boolean {
|
||||||
|
return type.flags & TypeFlags.TypeVariable ? true :
|
||||||
|
getObjectFlags(type) & ObjectFlags.Mapped ? isGenericIndexType(getConstraintTypeFromMappedType(<MappedType>type)) :
|
||||||
|
type.flags & TypeFlags.UnionOrIntersection ? forEach((<UnionOrIntersectionType>type).types, isGenericObjectType) :
|
||||||
|
false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isGenericIndexType(type: Type): boolean {
|
||||||
|
return type.flags & (TypeFlags.TypeVariable | TypeFlags.Index) ? true :
|
||||||
|
type.flags & TypeFlags.UnionOrIntersection ? forEach((<UnionOrIntersectionType>type).types, isGenericIndexType) :
|
||||||
|
false;
|
||||||
|
}
|
||||||
|
|
||||||
function getIndexedAccessType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode) {
|
function getIndexedAccessType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode) {
|
||||||
// If the index type is generic, if the object type is generic and doesn't originate in an expression,
|
// If the object type is a mapped type { [P in K]: E }, where K is generic, we instantiate E using a mapper
|
||||||
// or if the object type is a mapped type with a generic constraint, we are performing a higher-order
|
// that substitutes the index type for P. For example, for an index access { [P in K]: Box<T[P]> }[X], we
|
||||||
// index access where we cannot meaningfully access the properties of the object type. Note that for a
|
// construct the type Box<T[X]>.
|
||||||
// generic T and a non-generic K, we eagerly resolve T[K] if it originates in an expression. This is to
|
if (isGenericMappedType(objectType)) {
|
||||||
// preserve backwards compatibility. For example, an element access 'this["foo"]' has always been resolved
|
return getIndexedAccessForMappedType(<MappedType>objectType, indexType, accessNode);
|
||||||
// eagerly using the constraint type of 'this' at the given location.
|
}
|
||||||
if (maybeTypeOfKind(indexType, TypeFlags.TypeVariable | TypeFlags.Index) ||
|
// Otherwise, if the index type is generic, or if the object type is generic and doesn't originate in an
|
||||||
maybeTypeOfKind(objectType, TypeFlags.TypeVariable) && !(accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression) ||
|
// expression, we are performing a higher-order index access where we cannot meaningfully access the properties
|
||||||
isGenericMappedType(objectType)) {
|
// of the object type. Note that for a generic T and a non-generic K, we eagerly resolve T[K] if it originates
|
||||||
|
// in an expression. This is to preserve backwards compatibility. For example, an element access 'this["foo"]'
|
||||||
|
// has always been resolved eagerly using the constraint type of 'this' at the given location.
|
||||||
|
if (isGenericIndexType(indexType) || !(accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression) && isGenericObjectType(objectType)) {
|
||||||
if (objectType.flags & TypeFlags.Any) {
|
if (objectType.flags & TypeFlags.Any) {
|
||||||
return objectType;
|
return objectType;
|
||||||
}
|
}
|
||||||
// If the object type is a mapped type { [P in K]: E }, we instantiate E using a mapper that substitutes
|
// Defer the operation by creating an indexed access type.
|
||||||
// the index type for P. For example, for an index access { [P in K]: Box<T[P]> }[X], we construct the
|
|
||||||
// type Box<T[X]>.
|
|
||||||
if (isGenericMappedType(objectType)) {
|
|
||||||
return getIndexedAccessForMappedType(<MappedType>objectType, indexType, accessNode);
|
|
||||||
}
|
|
||||||
// Otherwise we defer the operation by creating an indexed access type.
|
|
||||||
const id = objectType.id + "," + indexType.id;
|
const id = objectType.id + "," + indexType.id;
|
||||||
let type = indexedAccessTypes.get(id);
|
let type = indexedAccessTypes.get(id);
|
||||||
if (!type) {
|
if (!type) {
|
||||||
|
|
Loading…
Reference in a new issue