Skip to content

Commit 4b96edf

Browse files
author
Andy
authored
Treat ... in jsdoc type as creating a synthetic rest parameter -- not as an array type (#19483)
* Treat `...` in jsdoc type as creating a synthetic rest parameter -- not as an array type * Change type parsing so `...T[]` parses as `...(T[])` and not `(...T)[]` * Replace the last parameter with ...args, and make access to it potentially undefined * Code review
1 parent 3d05952 commit 4b96edf

23 files changed

+336
-125
lines changed

src/compiler/checker.ts

Lines changed: 119 additions & 57 deletions
Large diffs are not rendered by default.

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3547,6 +3547,10 @@
35473547
"category": "Error",
35483548
"code": 8027
35493549
},
3550+
"JSDoc '...' may only appear in the last parameter of a signature.": {
3551+
"category": "Error",
3552+
"code": 8028
3553+
},
35503554
"Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clause.": {
35513555
"category": "Error",
35523556
"code": 9002

src/compiler/parser.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2678,8 +2678,6 @@ namespace ts {
26782678
return parseJSDocUnknownOrNullableType();
26792679
case SyntaxKind.FunctionKeyword:
26802680
return parseJSDocFunctionType();
2681-
case SyntaxKind.DotDotDotToken:
2682-
return parseJSDocNodeWithType(SyntaxKind.JSDocVariadicType);
26832681
case SyntaxKind.ExclamationToken:
26842682
return parseJSDocNodeWithType(SyntaxKind.JSDocNonNullableType);
26852683
case SyntaxKind.NoSubstitutionTemplateLiteral:
@@ -2819,6 +2817,12 @@ namespace ts {
28192817
switch (token()) {
28202818
case SyntaxKind.KeyOfKeyword:
28212819
return parseTypeOperator(SyntaxKind.KeyOfKeyword);
2820+
case SyntaxKind.DotDotDotToken: {
2821+
const result = createNode(SyntaxKind.JSDocVariadicType) as JSDocVariadicType;
2822+
nextToken();
2823+
result.type = parsePostfixTypeOrHigher();
2824+
return finishNode(result);
2825+
}
28222826
}
28232827
return parsePostfixTypeOrHigher();
28242828
}

src/compiler/utilities.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1626,16 +1626,22 @@ namespace ts {
16261626
return undefined;
16271627
}
16281628
const name = node.name.escapedText;
1629+
const decl = getHostSignatureFromJSDoc(node);
1630+
if (!decl) {
1631+
return undefined;
1632+
}
1633+
const parameter = find(decl.parameters, p => p.name.kind === SyntaxKind.Identifier && p.name.escapedText === name);
1634+
return parameter && parameter.symbol;
1635+
}
1636+
1637+
export function getHostSignatureFromJSDoc(node: JSDocParameterTag): FunctionLike | undefined {
16291638
const host = getJSDocHost(node);
16301639
const decl = getSourceOfAssignment(host) ||
16311640
getSingleInitializerOfVariableStatement(host) ||
16321641
getSingleVariableOfVariableStatement(host) ||
16331642
getNestedModuleDeclaration(host) ||
16341643
host;
1635-
if (decl && isFunctionLike(decl)) {
1636-
const parameter = find(decl.parameters, p => p.name.kind === SyntaxKind.Identifier && p.name.escapedText === name);
1637-
return parameter && parameter.symbol;
1638-
}
1644+
return decl && isFunctionLike(decl) ? decl : undefined;
16391645
}
16401646

16411647
export function getJSDocHost(node: JSDocTag): HasJSDoc {

tests/baselines/reference/jsFileCompilationRestParamJsDocFunction.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* @param {...*} args The arguments to invoke `func` with.
1010
* @returns {*} Returns the result of `func`.
1111
*/
12-
function apply(func, thisArg, args) {
12+
function apply(func, thisArg, ...args) {
1313
var length = args.length;
1414
switch (length) {
1515
case 0: return func.call(thisArg);
@@ -36,7 +36,11 @@ define("_apply", ["require", "exports"], function (require, exports) {
3636
* @param {...*} args The arguments to invoke `func` with.
3737
* @returns {*} Returns the result of `func`.
3838
*/
39-
function apply(func, thisArg, args) {
39+
function apply(func, thisArg) {
40+
var args = [];
41+
for (var _i = 2; _i < arguments.length; _i++) {
42+
args[_i - 2] = arguments[_i];
43+
}
4044
var length = args.length;
4145
switch (length) {
4246
case 0: return func.call(thisArg);

tests/baselines/reference/jsFileCompilationRestParamJsDocFunction.symbols

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* @param {...*} args The arguments to invoke `func` with.
1010
* @returns {*} Returns the result of `func`.
1111
*/
12-
function apply(func, thisArg, args) {
12+
function apply(func, thisArg, ...args) {
1313
>apply : Symbol(apply, Decl(_apply.js, 0, 0))
1414
>func : Symbol(func, Decl(_apply.js, 10, 15))
1515
>thisArg : Symbol(thisArg, Decl(_apply.js, 10, 20))

tests/baselines/reference/jsFileCompilationRestParamJsDocFunction.types

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
* @param {...*} args The arguments to invoke `func` with.
1010
* @returns {*} Returns the result of `func`.
1111
*/
12-
function apply(func, thisArg, args) {
13-
>apply : (func: Function, thisArg: any, args: any[]) => any
12+
function apply(func, thisArg, ...args) {
13+
>apply : (func: Function, thisArg: any, ...args: any[]) => any
1414
>func : Function
1515
>thisArg : any
1616
>args : any[]
@@ -84,5 +84,5 @@ function apply(func, thisArg, args) {
8484
}
8585

8686
export default apply;
87-
>apply : (func: Function, thisArg: any, args: any[]) => any
87+
>apply : (func: Function, thisArg: any, ...args: any[]) => any
8888

tests/baselines/reference/jsdocDisallowedInTypescript.errors.txt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(11,12): error TS255
77
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(13,14): error TS8020: JSDoc types can only be used inside documentation comments.
88
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(14,11): error TS8020: JSDoc types can only be used inside documentation comments.
99
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(15,8): error TS8020: JSDoc types can only be used inside documentation comments.
10+
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(16,5): error TS2322: Type 'boolean[]' is not assignable to type 'boolean | undefined'.
11+
Type 'boolean[]' is not assignable to type 'false'.
1012
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(16,15): error TS8020: JSDoc types can only be used inside documentation comments.
13+
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(16,15): error TS8028: JSDoc '...' may only appear in the last parameter of a signature.
1114
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(17,11): error TS8020: JSDoc types can only be used inside documentation comments.
1215
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(18,17): error TS8020: JSDoc types can only be used inside documentation comments.
1316
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(19,5): error TS2322: Type 'undefined' is not assignable to type 'number | null'.
@@ -16,9 +19,10 @@ tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(21,16): error TS802
1619
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(22,16): error TS8020: JSDoc types can only be used inside documentation comments.
1720
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(23,17): error TS8020: JSDoc types can only be used inside documentation comments.
1821
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(24,17): error TS8020: JSDoc types can only be used inside documentation comments.
22+
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(24,17): error TS8028: JSDoc '...' may only appear in the last parameter of a signature.
1923

2024

21-
==== tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts (18 errors) ====
25+
==== tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts (21 errors) ====
2226
// grammar error from checker
2327
var ara: Array.<number> = [1,2,3];
2428
~
@@ -53,8 +57,13 @@ tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(24,17): error TS802
5357
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5458
!!! error TS8020: JSDoc types can only be used inside documentation comments.
5559
var variadic: ...boolean = [true, false, true];
60+
~~~~~~~~
61+
!!! error TS2322: Type 'boolean[]' is not assignable to type 'boolean | undefined'.
62+
!!! error TS2322: Type 'boolean[]' is not assignable to type 'false'.
5663
~~~~~~~~~~
5764
!!! error TS8020: JSDoc types can only be used inside documentation comments.
65+
~~~~~~~~~~
66+
!!! error TS8028: JSDoc '...' may only appear in the last parameter of a signature.
5867
var most: !string = 'definite';
5968
~~~~~~~
6069
!!! error TS8020: JSDoc types can only be used inside documentation comments.
@@ -79,5 +88,7 @@ tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(24,17): error TS802
7988
var vars: Array<...number>;
8089
~~~~~~~~~
8190
!!! error TS8020: JSDoc types can only be used inside documentation comments.
91+
~~~~~~~~~
92+
!!! error TS8028: JSDoc '...' may only appear in the last parameter of a signature.
8293

8394

tests/baselines/reference/jsdocDisallowedInTypescript.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ var g: function(number, number): number = (n,m) => n + m;
6565
>m : number
6666

6767
var variadic: ...boolean = [true, false, true];
68-
>variadic : boolean[]
68+
>variadic : boolean | undefined
6969
>[true, false, true] : boolean[]
7070
>true : true
7171
>false : false
@@ -96,7 +96,7 @@ var anys: Array<*>;
9696
>Array : T[]
9797

9898
var vars: Array<...number>;
99-
>vars : number[][]
99+
>vars : (number | undefined)[]
100100
>Array : T[]
101101

102102

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
tests/cases/conformance/jsdoc/prefixPostfix.js(8,13): error TS8028: JSDoc '...' may only appear in the last parameter of a signature.
2+
tests/cases/conformance/jsdoc/prefixPostfix.js(9,12): error TS1014: A rest parameter must be last in a parameter list.
3+
tests/cases/conformance/jsdoc/prefixPostfix.js(10,12): error TS1014: A rest parameter must be last in a parameter list.
4+
tests/cases/conformance/jsdoc/prefixPostfix.js(11,12): error TS1014: A rest parameter must be last in a parameter list.
5+
tests/cases/conformance/jsdoc/prefixPostfix.js(12,12): error TS1014: A rest parameter must be last in a parameter list.
6+
tests/cases/conformance/jsdoc/prefixPostfix.js(13,12): error TS1014: A rest parameter must be last in a parameter list.
7+
tests/cases/conformance/jsdoc/prefixPostfix.js(14,12): error TS1014: A rest parameter must be last in a parameter list.
8+
9+
10+
==== tests/cases/conformance/jsdoc/prefixPostfix.js (7 errors) ====
11+
/**
12+
* @param {number![]} x - number[]
13+
* @param {!number[]} y - number[]
14+
* @param {(number[])!} z - number[]
15+
* @param {number?[]} a - (number | null)[]
16+
* @param {?number[]} b - number[] | null
17+
* @param {(number[])?} c - number[] | null
18+
* @param {?...number} d - number[] | null
19+
~~~~~~~~~
20+
!!! error TS8028: JSDoc '...' may only appear in the last parameter of a signature.
21+
* @param {...?number} e - (number | null)[]
22+
~~~~~~~~~~
23+
!!! error TS1014: A rest parameter must be last in a parameter list.
24+
* @param {...number?} f - number[] | null
25+
~~~~~~~~~~
26+
!!! error TS1014: A rest parameter must be last in a parameter list.
27+
* @param {...number!?} g - number[] | null
28+
~~~~~~~~~~~
29+
!!! error TS1014: A rest parameter must be last in a parameter list.
30+
* @param {...number?!} h - number[] | null
31+
~~~~~~~~~~~
32+
!!! error TS1014: A rest parameter must be last in a parameter list.
33+
* @param {...number[]} i - number[][]
34+
~~~~~~~~~~~
35+
!!! error TS1014: A rest parameter must be last in a parameter list.
36+
* @param {...number![]?} j - number[][] | null
37+
~~~~~~~~~~~~~
38+
!!! error TS1014: A rest parameter must be last in a parameter list.
39+
* @param {...number?[]!} k - (number[] | null)[]
40+
*/
41+
function f(x, y, z, a, b, c, d, e, f, g, h, i, j, k) {
42+
}
43+

0 commit comments

Comments
 (0)