mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-19 10:41:56 -05:00
Optimize deferred type references (#36607)
* Improve reasoning about when to create deferred type references * Accept new baselines * Fix minor issues * Handle default type arguments case in isDeferredTypeReferenceNode
This commit is contained in:
@@ -11090,7 +11090,7 @@ namespace ts {
|
||||
return errorType;
|
||||
}
|
||||
}
|
||||
if (node.kind === SyntaxKind.TypeReference && isAliasedType(node)) {
|
||||
if (node.kind === SyntaxKind.TypeReference && isDeferredTypeReferenceNode(<TypeReferenceNode>node, length(node.typeArguments) !== typeParameters.length)) {
|
||||
return createDeferredTypeReference(<GenericType>type, <TypeReferenceNode>node, /*mapper*/ undefined);
|
||||
}
|
||||
// In a type reference, the outer type parameters of the referenced class or interface are automatically
|
||||
@@ -11552,10 +11552,19 @@ namespace ts {
|
||||
return getTupleTypeOfArity(node.elementTypes.length, minLength, !!restElement, readonly, /*associatedNames*/ undefined);
|
||||
}
|
||||
|
||||
// Return true if the given type reference node is directly aliased or if it needs to be deferred
|
||||
// because it is possibly contained in a circular chain of eagerly resolved types.
|
||||
function isDeferredTypeReferenceNode(node: TypeReferenceNode | ArrayTypeNode | TupleTypeNode, hasDefaultTypeArguments?: boolean) {
|
||||
return !!getAliasSymbolForTypeNode(node) || isResolvedByTypeAlias(node) && (
|
||||
node.kind === SyntaxKind.ArrayType ? mayResolveTypeAlias(node.elementType) :
|
||||
node.kind === SyntaxKind.TupleType ? some(node.elementTypes, mayResolveTypeAlias) :
|
||||
hasDefaultTypeArguments || some(node.typeArguments, mayResolveTypeAlias));
|
||||
}
|
||||
|
||||
// Return true when the given node is transitively contained in type constructs that eagerly
|
||||
// resolve their constituent types. We include SyntaxKind.TypeReference because type arguments
|
||||
// of type aliases are eagerly resolved.
|
||||
function isAliasedType(node: Node): boolean {
|
||||
function isResolvedByTypeAlias(node: Node): boolean {
|
||||
const parent = node.parent;
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.ParenthesizedType:
|
||||
@@ -11565,13 +11574,44 @@ namespace ts {
|
||||
case SyntaxKind.IndexedAccessType:
|
||||
case SyntaxKind.ConditionalType:
|
||||
case SyntaxKind.TypeOperator:
|
||||
return isAliasedType(parent);
|
||||
return isResolvedByTypeAlias(parent);
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return true if resolving the given node (i.e. getTypeFromTypeNode) possibly causes resolution
|
||||
// of a type alias.
|
||||
function mayResolveTypeAlias(node: Node): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.TypeReference:
|
||||
return isJSDocTypeReference(node) || !!(resolveTypeReferenceName((<TypeReferenceNode>node).typeName, SymbolFlags.Type).flags & SymbolFlags.TypeAlias);
|
||||
case SyntaxKind.TypeQuery:
|
||||
return true;
|
||||
case SyntaxKind.TypeOperator:
|
||||
return (<TypeOperatorNode>node).operator !== SyntaxKind.UniqueKeyword && mayResolveTypeAlias((<TypeOperatorNode>node).type);
|
||||
case SyntaxKind.ParenthesizedType:
|
||||
case SyntaxKind.OptionalType:
|
||||
case SyntaxKind.JSDocOptionalType:
|
||||
case SyntaxKind.JSDocNullableType:
|
||||
case SyntaxKind.JSDocNonNullableType:
|
||||
case SyntaxKind.JSDocTypeExpression:
|
||||
return mayResolveTypeAlias((<ParenthesizedTypeNode | OptionalTypeNode | JSDocTypeReferencingNode>node).type);
|
||||
case SyntaxKind.RestType:
|
||||
return (<RestTypeNode>node).type.kind !== SyntaxKind.ArrayType || mayResolveTypeAlias((<ArrayTypeNode>(<RestTypeNode>node).type).elementType);
|
||||
case SyntaxKind.UnionType:
|
||||
case SyntaxKind.IntersectionType:
|
||||
return some((<UnionOrIntersectionTypeNode>node).types, mayResolveTypeAlias);
|
||||
case SyntaxKind.IndexedAccessType:
|
||||
return mayResolveTypeAlias((<IndexedAccessTypeNode>node).objectType) || mayResolveTypeAlias((<IndexedAccessTypeNode>node).indexType);
|
||||
case SyntaxKind.ConditionalType:
|
||||
return mayResolveTypeAlias((<ConditionalTypeNode>node).checkType) || mayResolveTypeAlias((<ConditionalTypeNode>node).extendsType) ||
|
||||
mayResolveTypeAlias((<ConditionalTypeNode>node).trueType) || mayResolveTypeAlias((<ConditionalTypeNode>node).falseType);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getTypeFromArrayOrTupleTypeNode(node: ArrayTypeNode | TupleTypeNode): Type {
|
||||
const links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
@@ -11579,7 +11619,7 @@ namespace ts {
|
||||
if (target === emptyGenericType) {
|
||||
links.resolvedType = emptyObjectType;
|
||||
}
|
||||
else if (isAliasedType(node)) {
|
||||
else if (isDeferredTypeReferenceNode(node)) {
|
||||
links.resolvedType = node.kind === SyntaxKind.TupleType && node.elementTypes.length === 0 ? target :
|
||||
createDeferredTypeReference(target, node, /*mapper*/ undefined);
|
||||
}
|
||||
@@ -12902,7 +12942,7 @@ namespace ts {
|
||||
return links.resolvedType;
|
||||
}
|
||||
|
||||
function getAliasSymbolForTypeNode(node: TypeNode) {
|
||||
function getAliasSymbolForTypeNode(node: Node) {
|
||||
let host = node.parent;
|
||||
while (isParenthesizedTypeNode(host) || isTypeOperatorNode(host) && host.operator === SyntaxKind.ReadonlyKeyword) {
|
||||
host = host.parent;
|
||||
|
||||
Reference in New Issue
Block a user