@@ -74,14 +74,41 @@ function formatType(type: string, options?: Options): string {
7474 try {
7575 const TYPE_START = "type name = " ;
7676
77- let pretty = format ( `${ TYPE_START } ${ type } ` , {
77+ let pretty = type ;
78+
79+ // Rest parameter types start with "...". This is supported by TS and JSDoc
80+ // but it's implemented in a weird way in TS. TS will only acknowledge the
81+ // "..." if the function parameter is a rest parameter. In this case, TS
82+ // will interpret `...T` as `T[]`. But we can't just convert "..." to arrays
83+ // because of @callback types. In @callback types `...T` and `T[]` are not
84+ // equivalent, so we have to support "..." as is.
85+ //
86+ // This formatting itself is rather simple. If `...T` is detected, it will
87+ // be replaced with `T[]` and formatted. At the end, the outer array will
88+ // be removed and "..." will be added again.
89+ //
90+ // As a consequence, union types will get an additional pair of parentheses
91+ // (e.g. `...A|B` -> `...(A|B)`). This is technically unnecessary but it
92+ // makes the operator precedence very clear.
93+ //
94+ // https://www.typescriptlang.org/docs/handbook/functions.html#rest-parameters
95+ let rest = false ;
96+ if ( pretty . startsWith ( "..." ) ) {
97+ rest = true ;
98+ pretty = `(${ pretty . slice ( 3 ) } )[]` ;
99+ }
100+
101+ pretty = format ( `${ TYPE_START } ${ pretty } ` , {
78102 ...options ,
79103 parser : "typescript" ,
80104 } ) ;
81105 pretty = pretty . slice ( TYPE_START . length ) ;
82-
83106 pretty = pretty . replace ( / [ ; \n ] * $ / g, "" ) ;
84107
108+ if ( rest ) {
109+ pretty = "..." + pretty . replace ( / \[ \s * \] $ / , "" ) ;
110+ }
111+
85112 return pretty ;
86113 } catch ( error ) {
87114 // console.log("jsdoc-parser", error);
0 commit comments