Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 22919d5

Browse filesBrowse files
authored
JSDoc:positional matching of destructured params (#23307)
* JSDoc:positional matching of destructured params 1. When looking up tags for a parameter whose name is a binding pattern, use the index of the parameter to get the type. 2. When reporting errors for `@param` tags with no matching parameter name, do not report the error for tags whose index in the `@param` tag list matches the index of a parameter whose name is a binding pattern. * Change to an assert * Improve comment text
1 parent 4b706fc commit 22919d5
Copy full SHA for 22919d5

6 files changed

+405-4Lines changed: 405 additions & 4 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/compiler/checker.ts‎

Copy file name to clipboardExpand all lines: src/compiler/checker.ts
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21871,6 +21871,10 @@ namespace ts {
2187121871
// and give a better error message when the host function mentions `arguments`
2187221872
// but the tag doesn't have an array type
2187321873
if (decl) {
21874+
const i = getJSDocTags(decl).filter(isJSDocParameterTag).indexOf(node);
21875+
if (i > -1 && i < decl.parameters.length && isBindingPattern(decl.parameters[i].name)) {
21876+
return;
21877+
}
2187421878
if (!containsArgumentsReference(decl)) {
2187521879
error(node.name,
2187621880
Diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name,
Collapse file

‎src/compiler/utilities.ts‎

Copy file name to clipboardExpand all lines: src/compiler/utilities.ts
+14-4Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4632,11 +4632,21 @@ namespace ts {
46324632
* parameters by name and binding patterns do not have a name.
46334633
*/
46344634
export function getJSDocParameterTags(param: ParameterDeclaration): ReadonlyArray<JSDocParameterTag> {
4635-
if (param.name && isIdentifier(param.name)) {
4636-
const name = param.name.escapedText;
4637-
return getJSDocTags(param.parent).filter((tag): tag is JSDocParameterTag => isJSDocParameterTag(tag) && isIdentifier(tag.name) && tag.name.escapedText === name);
4635+
if (param.name) {
4636+
if (isIdentifier(param.name)) {
4637+
const name = param.name.escapedText;
4638+
return getJSDocTags(param.parent).filter((tag): tag is JSDocParameterTag => isJSDocParameterTag(tag) && isIdentifier(tag.name) && tag.name.escapedText === name);
4639+
}
4640+
else {
4641+
const i = param.parent.parameters.indexOf(param);
4642+
Debug.assert(i > -1, "Parameters should always be in their parents' parameter list");
4643+
const paramTags = getJSDocTags(param.parent).filter(isJSDocParameterTag);
4644+
if (i < paramTags.length) {
4645+
return [paramTags[i]];
4646+
}
4647+
}
46384648
}
4639-
// a binding pattern doesn't have a name, so it's not possible to match it a JSDoc parameter, which is identified by name
4649+
// return empty array for: out-of-order binding patterns and JSDoc function syntax, which has un-named parameters
46404650
return emptyArray;
46414651
}
46424652

Collapse file
+82Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
tests/cases/conformance/jsdoc/0.js(56,20): error TS8024: JSDoc '@param' tag has name 'obj', but there is no parameter with that name.
2+
tests/cases/conformance/jsdoc/0.js(61,19): error TS2459: Type 'string' has no property 'a' and no string index signature.
3+
tests/cases/conformance/jsdoc/0.js(61,22): error TS2459: Type 'string' has no property 'b' and no string index signature.
4+
tests/cases/conformance/jsdoc/0.js(63,20): error TS8024: JSDoc '@param' tag has name 'y', but there is no parameter with that name.
5+
6+
7+
==== tests/cases/conformance/jsdoc/0.js (4 errors) ====
8+
// Object literal syntax
9+
/**
10+
* @param {{a: string, b: string}} obj
11+
* @param {string} x
12+
*/
13+
function good1({a, b}, x) {}
14+
/**
15+
* @param {{a: string, b: string}} obj
16+
* @param {{c: number, d: number}} OBJECTION
17+
*/
18+
function good2({a, b}, {c, d}) {}
19+
/**
20+
* @param {number} x
21+
* @param {{a: string, b: string}} obj
22+
* @param {string} y
23+
*/
24+
function good3(x, {a, b}, y) {}
25+
/**
26+
* @param {{a: string, b: string}} obj
27+
*/
28+
function good4({a, b}) {}
29+
30+
// nested object syntax
31+
/**
32+
* @param {Object} obj
33+
* @param {string} obj.a - this is like the saddest way to specify a type
34+
* @param {string} obj.b - but it sure does allow a lot of documentation
35+
* @param {string} x
36+
*/
37+
function good5({a, b}, x) {}
38+
/**
39+
* @param {Object} obj
40+
* @param {string} obj.a
41+
* @param {string} obj.b - but it sure does allow a lot of documentation
42+
* @param {Object} OBJECTION - documentation here too
43+
* @param {string} OBJECTION.c
44+
* @param {string} OBJECTION.d - meh
45+
*/
46+
function good6({a, b}, {c, d}) {}
47+
/**
48+
* @param {number} x
49+
* @param {Object} obj
50+
* @param {string} obj.a
51+
* @param {string} obj.b
52+
* @param {string} y
53+
*/
54+
function good7(x, {a, b}, y) {}
55+
/**
56+
* @param {Object} obj
57+
* @param {string} obj.a
58+
* @param {string} obj.b
59+
*/
60+
function good8({a, b}) {}
61+
62+
/**
63+
* @param {object} obj - this type gets ignored
64+
~~~
65+
!!! error TS8024: JSDoc '@param' tag has name 'obj', but there is no parameter with that name.
66+
* @param {string} obj.a
67+
* @param {string} obj.b - and x's type gets used for both parameters
68+
* @param {string} x
69+
*/
70+
function bad1(x, {a, b}) {}
71+
~
72+
!!! error TS2459: Type 'string' has no property 'a' and no string index signature.
73+
~
74+
!!! error TS2459: Type 'string' has no property 'b' and no string index signature.
75+
/**
76+
* @param {string} y - here, y's type gets ignored but obj's is fine
77+
~
78+
!!! error TS8024: JSDoc '@param' tag has name 'y', but there is no parameter with that name.
79+
* @param {{a: string, b: string}} obj
80+
*/
81+
function bad2(x, {a, b}) {}
82+
Collapse file
+117Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
=== tests/cases/conformance/jsdoc/0.js ===
2+
// Object literal syntax
3+
/**
4+
* @param {{a: string, b: string}} obj
5+
* @param {string} x
6+
*/
7+
function good1({a, b}, x) {}
8+
>good1 : Symbol(good1, Decl(0.js, 0, 0))
9+
>a : Symbol(a, Decl(0.js, 5, 16))
10+
>b : Symbol(b, Decl(0.js, 5, 18))
11+
>x : Symbol(x, Decl(0.js, 5, 22))
12+
13+
/**
14+
* @param {{a: string, b: string}} obj
15+
* @param {{c: number, d: number}} OBJECTION
16+
*/
17+
function good2({a, b}, {c, d}) {}
18+
>good2 : Symbol(good2, Decl(0.js, 5, 28))
19+
>a : Symbol(a, Decl(0.js, 10, 16))
20+
>b : Symbol(b, Decl(0.js, 10, 18))
21+
>c : Symbol(c, Decl(0.js, 10, 24))
22+
>d : Symbol(d, Decl(0.js, 10, 26))
23+
24+
/**
25+
* @param {number} x
26+
* @param {{a: string, b: string}} obj
27+
* @param {string} y
28+
*/
29+
function good3(x, {a, b}, y) {}
30+
>good3 : Symbol(good3, Decl(0.js, 10, 33))
31+
>x : Symbol(x, Decl(0.js, 16, 15))
32+
>a : Symbol(a, Decl(0.js, 16, 19))
33+
>b : Symbol(b, Decl(0.js, 16, 21))
34+
>y : Symbol(y, Decl(0.js, 16, 25))
35+
36+
/**
37+
* @param {{a: string, b: string}} obj
38+
*/
39+
function good4({a, b}) {}
40+
>good4 : Symbol(good4, Decl(0.js, 16, 31))
41+
>a : Symbol(a, Decl(0.js, 20, 16))
42+
>b : Symbol(b, Decl(0.js, 20, 18))
43+
44+
// nested object syntax
45+
/**
46+
* @param {Object} obj
47+
* @param {string} obj.a - this is like the saddest way to specify a type
48+
* @param {string} obj.b - but it sure does allow a lot of documentation
49+
* @param {string} x
50+
*/
51+
function good5({a, b}, x) {}
52+
>good5 : Symbol(good5, Decl(0.js, 20, 25))
53+
>a : Symbol(a, Decl(0.js, 29, 16))
54+
>b : Symbol(b, Decl(0.js, 29, 18))
55+
>x : Symbol(x, Decl(0.js, 29, 22))
56+
57+
/**
58+
* @param {Object} obj
59+
* @param {string} obj.a
60+
* @param {string} obj.b - but it sure does allow a lot of documentation
61+
* @param {Object} OBJECTION - documentation here too
62+
* @param {string} OBJECTION.c
63+
* @param {string} OBJECTION.d - meh
64+
*/
65+
function good6({a, b}, {c, d}) {}
66+
>good6 : Symbol(good6, Decl(0.js, 29, 28))
67+
>a : Symbol(a, Decl(0.js, 38, 16))
68+
>b : Symbol(b, Decl(0.js, 38, 18))
69+
>c : Symbol(c, Decl(0.js, 38, 24))
70+
>d : Symbol(d, Decl(0.js, 38, 26))
71+
72+
/**
73+
* @param {number} x
74+
* @param {Object} obj
75+
* @param {string} obj.a
76+
* @param {string} obj.b
77+
* @param {string} y
78+
*/
79+
function good7(x, {a, b}, y) {}
80+
>good7 : Symbol(good7, Decl(0.js, 38, 33))
81+
>x : Symbol(x, Decl(0.js, 46, 15))
82+
>a : Symbol(a, Decl(0.js, 46, 19))
83+
>b : Symbol(b, Decl(0.js, 46, 21))
84+
>y : Symbol(y, Decl(0.js, 46, 25))
85+
86+
/**
87+
* @param {Object} obj
88+
* @param {string} obj.a
89+
* @param {string} obj.b
90+
*/
91+
function good8({a, b}) {}
92+
>good8 : Symbol(good8, Decl(0.js, 46, 31))
93+
>a : Symbol(a, Decl(0.js, 52, 16))
94+
>b : Symbol(b, Decl(0.js, 52, 18))
95+
96+
/**
97+
* @param {object} obj - this type gets ignored
98+
* @param {string} obj.a
99+
* @param {string} obj.b - and x's type gets used for both parameters
100+
* @param {string} x
101+
*/
102+
function bad1(x, {a, b}) {}
103+
>bad1 : Symbol(bad1, Decl(0.js, 52, 25))
104+
>x : Symbol(x, Decl(0.js, 60, 14))
105+
>a : Symbol(a, Decl(0.js, 60, 18))
106+
>b : Symbol(b, Decl(0.js, 60, 20))
107+
108+
/**
109+
* @param {string} y - here, y's type gets ignored but obj's is fine
110+
* @param {{a: string, b: string}} obj
111+
*/
112+
function bad2(x, {a, b}) {}
113+
>bad2 : Symbol(bad2, Decl(0.js, 60, 27))
114+
>x : Symbol(x, Decl(0.js, 65, 14))
115+
>a : Symbol(a, Decl(0.js, 65, 18))
116+
>b : Symbol(b, Decl(0.js, 65, 20))
117+
Collapse file
+117Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
=== tests/cases/conformance/jsdoc/0.js ===
2+
// Object literal syntax
3+
/**
4+
* @param {{a: string, b: string}} obj
5+
* @param {string} x
6+
*/
7+
function good1({a, b}, x) {}
8+
>good1 : ({ a, b }: { a: string; b: string; }, x: string) => void
9+
>a : string
10+
>b : string
11+
>x : string
12+
13+
/**
14+
* @param {{a: string, b: string}} obj
15+
* @param {{c: number, d: number}} OBJECTION
16+
*/
17+
function good2({a, b}, {c, d}) {}
18+
>good2 : ({ a, b }: { a: string; b: string; }, { c, d }: { c: number; d: number; }) => void
19+
>a : string
20+
>b : string
21+
>c : number
22+
>d : number
23+
24+
/**
25+
* @param {number} x
26+
* @param {{a: string, b: string}} obj
27+
* @param {string} y
28+
*/
29+
function good3(x, {a, b}, y) {}
30+
>good3 : (x: number, { a, b }: { a: string; b: string; }, y: string) => void
31+
>x : number
32+
>a : string
33+
>b : string
34+
>y : string
35+
36+
/**
37+
* @param {{a: string, b: string}} obj
38+
*/
39+
function good4({a, b}) {}
40+
>good4 : ({ a, b }: { a: string; b: string; }) => void
41+
>a : string
42+
>b : string
43+
44+
// nested object syntax
45+
/**
46+
* @param {Object} obj
47+
* @param {string} obj.a - this is like the saddest way to specify a type
48+
* @param {string} obj.b - but it sure does allow a lot of documentation
49+
* @param {string} x
50+
*/
51+
function good5({a, b}, x) {}
52+
>good5 : ({ a, b }: { a: string; b: string; }, x: string) => void
53+
>a : string
54+
>b : string
55+
>x : string
56+
57+
/**
58+
* @param {Object} obj
59+
* @param {string} obj.a
60+
* @param {string} obj.b - but it sure does allow a lot of documentation
61+
* @param {Object} OBJECTION - documentation here too
62+
* @param {string} OBJECTION.c
63+
* @param {string} OBJECTION.d - meh
64+
*/
65+
function good6({a, b}, {c, d}) {}
66+
>good6 : ({ a, b }: { a: string; b: string; }, { c, d }: { c: string; d: string; }) => void
67+
>a : string
68+
>b : string
69+
>c : string
70+
>d : string
71+
72+
/**
73+
* @param {number} x
74+
* @param {Object} obj
75+
* @param {string} obj.a
76+
* @param {string} obj.b
77+
* @param {string} y
78+
*/
79+
function good7(x, {a, b}, y) {}
80+
>good7 : (x: number, { a, b }: { a: string; b: string; }, y: string) => void
81+
>x : number
82+
>a : string
83+
>b : string
84+
>y : string
85+
86+
/**
87+
* @param {Object} obj
88+
* @param {string} obj.a
89+
* @param {string} obj.b
90+
*/
91+
function good8({a, b}) {}
92+
>good8 : ({ a, b }: { a: string; b: string; }) => void
93+
>a : string
94+
>b : string
95+
96+
/**
97+
* @param {object} obj - this type gets ignored
98+
* @param {string} obj.a
99+
* @param {string} obj.b - and x's type gets used for both parameters
100+
* @param {string} x
101+
*/
102+
function bad1(x, {a, b}) {}
103+
>bad1 : (x: string, { a, b }: string) => void
104+
>x : string
105+
>a : any
106+
>b : any
107+
108+
/**
109+
* @param {string} y - here, y's type gets ignored but obj's is fine
110+
* @param {{a: string, b: string}} obj
111+
*/
112+
function bad2(x, {a, b}) {}
113+
>bad2 : (x: any, { a, b }: { a: string; b: string; }) => void
114+
>x : any
115+
>a : string
116+
>b : string
117+

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.