Skip to content

Commit b4018a2

Browse files
author
Andy
authored
Handle @typedef tag with missing type (#18662)
* Handle @typedef tag with missing type * Add single quotes to diagnostic * Remove redundant jsdoc checking (now done on every source element) * Update baselines
1 parent 5a0c60a commit b4018a2

7 files changed

+110
-6
lines changed

src/compiler/checker.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5124,7 +5124,9 @@ namespace ts {
51245124

51255125
const declaration = <JSDocTypedefTag | TypeAliasDeclaration>find(symbol.declarations, d =>
51265126
d.kind === SyntaxKind.JSDocTypedefTag || d.kind === SyntaxKind.TypeAliasDeclaration);
5127-
let type = getTypeFromTypeNode(declaration.kind === SyntaxKind.JSDocTypedefTag ? declaration.typeExpression : declaration.type);
5127+
const typeNode = declaration.kind === SyntaxKind.JSDocTypedefTag ? declaration.typeExpression : declaration.type;
5128+
// If typeNode is missing, we will error in checkJSDocTypedefTag.
5129+
let type = typeNode ? getTypeFromTypeNode(typeNode) : unknownType;
51285130

51295131
if (popTypeResolution()) {
51305132
const typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
@@ -19779,11 +19781,11 @@ namespace ts {
1977919781
}
1978019782
}
1978119783

19782-
function checkJSDoc(node: FunctionDeclaration | MethodDeclaration) {
19783-
if (!isInJavaScriptFile(node)) {
19784-
return;
19784+
function checkJSDocTypedefTag(node: JSDocTypedefTag) {
19785+
if (!node.typeExpression) {
19786+
// If the node had `@property` tags, `typeExpression` would have been set to the first property tag.
19787+
error(node.name, Diagnostics.JSDoc_typedef_tag_should_either_have_a_type_annotation_or_be_followed_by_property_or_member_tags);
1978519788
}
19786-
forEach(node.jsDoc, checkSourceElement);
1978719789
}
1978819790

1978919791
function checkJSDocComment(node: JSDoc) {
@@ -19795,7 +19797,6 @@ namespace ts {
1979519797
}
1979619798

1979719799
function checkFunctionOrMethodDeclaration(node: FunctionDeclaration | MethodDeclaration): void {
19798-
checkJSDoc(node);
1979919800
checkDecorators(node);
1980019801
checkSignatureDeclaration(node);
1980119802
const functionFlags = getFunctionFlags(node);
@@ -22429,6 +22430,12 @@ namespace ts {
2242922430
return;
2243022431
}
2243122432

22433+
if (isInJavaScriptFile(node) && (node as JSDocContainer).jsDoc) {
22434+
for (const jsdoc of (node as JSDocContainer).jsDoc) {
22435+
checkJSDocComment(jsdoc);
22436+
}
22437+
}
22438+
2243222439
const kind = node.kind;
2243322440
if (cancellationToken) {
2243422441
// Only bother checking on a few construct kinds. We don't want to be excessively
@@ -22483,6 +22490,8 @@ namespace ts {
2248322490
case SyntaxKind.ParenthesizedType:
2248422491
case SyntaxKind.TypeOperator:
2248522492
return checkSourceElement((<ParenthesizedTypeNode | TypeOperatorNode>node).type);
22493+
case SyntaxKind.JSDocTypedefTag:
22494+
return checkJSDocTypedefTag(node as JSDocTypedefTag);
2248622495
case SyntaxKind.JSDocComment:
2248722496
return checkJSDocComment(node as JSDoc);
2248822497
case SyntaxKind.JSDocParameterTag:

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3507,6 +3507,10 @@
35073507
"category": "Error",
35083508
"code": 8020
35093509
},
3510+
"JSDoc '@typedef' tag should either have a type annotation or be followed by '@property' or '@member' tags.": {
3511+
"category": "Error",
3512+
"code": 8021
3513+
},
35103514
"Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clause.": {
35113515
"category": "Error",
35123516
"code": 9002
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/a.js(2,14): error TS8021: JSDoc '@typedef' tag should either have a type annotation or be followed by '@property' or '@member' tags.
2+
/a.js(12,11): error TS1005: '{' expected.
3+
4+
5+
==== /a.js (2 errors) ====
6+
// Bad: missing a type
7+
/** @typedef T */
8+
~
9+
!!! error TS8021: JSDoc '@typedef' tag should either have a type annotation or be followed by '@property' or '@member' tags.
10+
11+
const t = 0;
12+
13+
// OK: missing a type, but have property tags.
14+
/**
15+
* @typedef Person
16+
* @property {string} name
17+
*/
18+
19+
/** @type Person */
20+
~~~~~~
21+
!!! error TS1005: '{' expected.
22+
const person = { name: "" };
23+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
=== /a.js ===
2+
// Bad: missing a type
3+
/** @typedef T */
4+
5+
const t = 0;
6+
>t : Symbol(t, Decl(a.js, 3, 5))
7+
8+
// OK: missing a type, but have property tags.
9+
/**
10+
* @typedef Person
11+
* @property {string} name
12+
*/
13+
14+
/** @type Person */
15+
const person = { name: "" };
16+
>person : Symbol(person, Decl(a.js, 12, 5))
17+
>name : Symbol(name, Decl(a.js, 12, 16))
18+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
=== /a.js ===
2+
// Bad: missing a type
3+
/** @typedef T */
4+
5+
const t = 0;
6+
>t : 0
7+
>0 : 0
8+
9+
// OK: missing a type, but have property tags.
10+
/**
11+
* @typedef Person
12+
* @property {string} name
13+
*/
14+
15+
/** @type Person */
16+
const person = { name: "" };
17+
>person : { [x: string]: any; name: string; }
18+
>{ name: "" } : { [x: string]: any; name: string; }
19+
>name : string
20+
>"" : ""
21+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// @allowJs: true
2+
// @checkJs: true
3+
// @noEmit: true
4+
5+
// @Filename: /a.js
6+
// Bad: missing a type
7+
/** @typedef T */
8+
9+
const t = 0;
10+
11+
// OK: missing a type, but have property tags.
12+
/**
13+
* @typedef Person
14+
* @property {string} name
15+
*/
16+
17+
/** @type Person */
18+
const person = { name: "" };
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @allowJs: true
4+
5+
// @Filename: /a.js
6+
/////**
7+
//// * @typedef /**/A
8+
//// */
9+
////var x;
10+
11+
verify.quickInfoAt("", "type A = any");

0 commit comments

Comments
 (0)