@@ -4882,7 +4882,16 @@ namespace ts {
48824882 }
48834883
48844884 function getBaseTypeNodeOfClass(type: InterfaceType): ExpressionWithTypeArguments {
4885- return getClassExtendsHeritageClauseElement(<ClassLikeDeclaration>type.symbol.valueDeclaration);
4885+ const decl = <ClassLikeDeclaration>type.symbol.valueDeclaration;
4886+ if (isInJavaScriptFile(decl)) {
4887+ // Prefer an @augments tag because it may have type parameters.
4888+ const tag = getJSDocAugmentsTag(decl);
4889+ if (tag) {
4890+ return tag.class;
4891+ }
4892+ }
4893+
4894+ return getClassExtendsHeritageClauseElement(decl);
48864895 }
48874896
48884897 function getConstructorsForTypeArguments(type: Type, typeArgumentNodes: ReadonlyArray<TypeNode>, location: Node): Signature[] {
@@ -4986,15 +4995,6 @@ namespace ts {
49864995 baseType = getReturnTypeOfSignature(constructors[0]);
49874996 }
49884997
4989- // In a JS file, you can use the @augments jsdoc tag to specify a base type with type parameters
4990- const valueDecl = type.symbol.valueDeclaration;
4991- if (valueDecl && isInJavaScriptFile(valueDecl)) {
4992- const augTag = getJSDocAugmentsTag(type.symbol.valueDeclaration);
4993- if (augTag && augTag.typeExpression && augTag.typeExpression.type) {
4994- baseType = getTypeFromTypeNode(augTag.typeExpression.type);
4995- }
4996- }
4997-
49984998 if (baseType === unknownType) {
49994999 return;
50005000 }
@@ -5003,7 +5003,7 @@ namespace ts {
50035003 return;
50045004 }
50055005 if (type === baseType || hasBaseType(baseType, type)) {
5006- error(valueDecl , Diagnostics.Type_0_recursively_references_itself_as_a_base_type,
5006+ error(type.symbol.valueDeclaration , Diagnostics.Type_0_recursively_references_itself_as_a_base_type,
50075007 typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType));
50085008 return;
50095009 }
@@ -19788,6 +19788,36 @@ namespace ts {
1978819788 }
1978919789 }
1979019790
19791+ function checkJSDocAugmentsTag(node: JSDocAugmentsTag): void {
19792+ const cls = getNodeCommentedByJSDocTag(node);
19793+ if (!isClassDeclaration(cls) && !isClassExpression(cls)) {
19794+ error(cls, Diagnostics.JSDoc_augments_tag_will_be_ignored_if_not_attached_to_a_class_declaration);
19795+ return;
19796+ }
19797+
19798+ const name: Identifier = node.class.expression.kind === SyntaxKind.PropertyAccessExpression ? (node.class.expression as PropertyAccessExpression).name : (node.class.expression as Identifier);
19799+ const extend = getClassExtendsHeritageClauseElement(cls);
19800+ if (extend) {
19801+ const className = getClassName(extend.expression);
19802+ if (className && name.escapedText !== className.escapedText) {
19803+ error(name, Diagnostics.JSDoc_augments_tag_declares_to_extend_0_but_actual_class_augments_1,
19804+ unescapeLeadingUnderscores(name.escapedText),
19805+ unescapeLeadingUnderscores(className.escapedText));
19806+ }
19807+ }
19808+ }
19809+
19810+ function getClassName(node: Expression): Identifier | undefined {
19811+ switch (node.kind) {
19812+ case SyntaxKind.Identifier:
19813+ return node as Identifier;
19814+ case SyntaxKind.PropertyAccessExpression:
19815+ return (node as PropertyAccessExpression).name;
19816+ default:
19817+ return undefined;
19818+ }
19819+ }
19820+
1979119821 function checkJSDocComment(node: JSDoc) {
1979219822 if ((node as JSDoc).tags) {
1979319823 for (const tag of (node as JSDoc).tags) {
@@ -22490,6 +22520,8 @@ namespace ts {
2249022520 case SyntaxKind.ParenthesizedType:
2249122521 case SyntaxKind.TypeOperator:
2249222522 return checkSourceElement((<ParenthesizedTypeNode | TypeOperatorNode>node).type);
22523+ case SyntaxKind.JSDocAugmentsTag:
22524+ return checkJSDocAugmentsTag(node as JSDocAugmentsTag);
2249322525 case SyntaxKind.JSDocTypedefTag:
2249422526 return checkJSDocTypedefTag(node as JSDocTypedefTag);
2249522527 case SyntaxKind.JSDocComment:
0 commit comments