Skip to content

Commit 7959bd0

Browse files
author
Andy
authored
Check JSDoc @param tag names (#18777)
1 parent 4bba6ee commit 7959bd0

File tree

7 files changed

+120
-1
lines changed

7 files changed

+120
-1
lines changed

src/compiler/checker.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19792,6 +19792,15 @@ namespace ts {
1979219792
}
1979319793
}
1979419794

19795+
function checkJSDocParameterTag(node: JSDocParameterTag) {
19796+
checkSourceElement(node.typeExpression);
19797+
if (!getParameterSymbolFromJSDoc(node)) {
19798+
error(node.name,
19799+
Diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name,
19800+
unescapeLeadingUnderscores((node.name.kind === SyntaxKind.QualifiedName ? node.name.right : node.name).escapedText));
19801+
}
19802+
}
19803+
1979519804
function checkJSDocAugmentsTag(node: JSDocAugmentsTag): void {
1979619805
const cls = getJSDocHost(node);
1979719806
if (!isClassDeclaration(cls) && !isClassExpression(cls)) {
@@ -22523,7 +22532,7 @@ namespace ts {
2252322532
case SyntaxKind.JSDocTypedefTag:
2252422533
return checkJSDocTypedefTag(node as JSDocTypedefTag);
2252522534
case SyntaxKind.JSDocParameterTag:
22526-
return checkSourceElement((node as JSDocParameterTag).typeExpression);
22535+
return checkJSDocParameterTag(node as JSDocParameterTag);
2252722536
case SyntaxKind.JSDocFunctionType:
2252822537
checkSignatureDeclaration(node as JSDocFunctionType);
2252922538
// falls through

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3519,6 +3519,10 @@
35193519
"category": "Error",
35203520
"code": 8023
35213521
},
3522+
"JSDoc '@param' tag has name '{0}', but there is no parameter with that name.": {
3523+
"category": "Error",
3524+
"code": 8024
3525+
},
35223526
"Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clause.": {
35233527
"category": "Error",
35243528
"code": 9002
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/a.js(1,21): error TS8024: JSDoc '@param' tag has name 'colour', but there is no parameter with that name.
2+
3+
4+
==== /a.js (1 errors) ====
5+
/** @param {string} colour */
6+
~~~~~~
7+
!!! error TS8024: JSDoc '@param' tag has name 'colour', but there is no parameter with that name.
8+
function f(color) {}
9+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
=== /a.js ===
2+
/** @param {string} colour */
3+
function f(color) {}
4+
>f : Symbol(f, Decl(a.js, 0, 0))
5+
>color : Symbol(color, Decl(a.js, 1, 11))
6+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
=== /a.js ===
2+
/** @param {string} colour */
3+
function f(color) {}
4+
>f : (color: any) => void
5+
>color : any
6+
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
tests/cases/conformance/jsdoc/0.js(3,20): error TS8024: JSDoc '@param' tag has name 'unrelated', but there is no parameter with that name.
2+
3+
4+
==== tests/cases/conformance/jsdoc/0.js (1 errors) ====
5+
/**
6+
* @param {Object} notSpecial
7+
* @param {string} unrelated - not actually related because it's not notSpecial.unrelated
8+
~~~~~~~~~
9+
!!! error TS8024: JSDoc '@param' tag has name 'unrelated', but there is no parameter with that name.
10+
*/
11+
function normal(notSpecial) {
12+
notSpecial; // should just be 'any'
13+
}
14+
normal(12);
15+
16+
/**
17+
* @param {Object} opts1 doc1
18+
* @param {string} opts1.x doc2
19+
* @param {string=} opts1.y doc3
20+
* @param {string} [opts1.z] doc4
21+
* @param {string} [opts1.w="hi"] doc5
22+
*/
23+
function foo1(opts1) {
24+
opts1.x;
25+
}
26+
27+
foo1({x: 'abc'});
28+
29+
/**
30+
* @param {Object[]} opts2
31+
* @param {string} opts2[].anotherX
32+
* @param {string=} opts2[].anotherY
33+
*/
34+
function foo2(/** @param opts2 bad idea theatre! */opts2) {
35+
opts2[0].anotherX;
36+
}
37+
38+
foo2([{anotherX: "world"}]);
39+
40+
/**
41+
* @param {object} opts3
42+
* @param {string} opts3.x
43+
*/
44+
function foo3(opts3) {
45+
opts3.x;
46+
}
47+
foo3({x: 'abc'});
48+
49+
/**
50+
* @param {object[]} opts4
51+
* @param {string} opts4[].x
52+
* @param {string=} opts4[].y
53+
* @param {string} [opts4[].z]
54+
* @param {string} [opts4[].w="hi"]
55+
*/
56+
function foo4(opts4) {
57+
opts4[0].x;
58+
}
59+
60+
foo4([{ x: 'hi' }]);
61+
62+
/**
63+
* @param {object[]} opts5 - Let's test out some multiple nesting levels
64+
* @param {string} opts5[].help - (This one is just normal)
65+
* @param {object} opts5[].what - Look at us go! Here's the first nest!
66+
* @param {string} opts5[].what.a - (Another normal one)
67+
* @param {Object[]} opts5[].what.bad - Now we're nesting inside a nested type
68+
* @param {string} opts5[].what.bad[].idea - I don't think you can get back out of this level...
69+
* @param {boolean} opts5[].what.bad[].oh - Oh ... that's how you do it.
70+
* @param {number} opts5[].unnest - Here we are almost all the way back at the beginning.
71+
*/
72+
function foo5(opts5) {
73+
opts5[0].what.bad[0].idea;
74+
opts5[0].unnest;
75+
}
76+
77+
foo5([{ help: "help", what: { a: 'a', bad: [{ idea: 'idea', oh: false }] }, unnest: 1 }]);
78+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// @allowJs: true
2+
// @checkJs: true
3+
// @noEmit: true
4+
5+
// @Filename: /a.js
6+
/** @param {string} colour */
7+
function f(color) {}

0 commit comments

Comments
 (0)