diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index e27215e7a87..a7fac539da5 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -8043,6 +8043,9 @@ namespace ts { function parseTemplateTagTypeParameter() { const typeParameterPos = getNodePos(); const name = parseJSDocIdentifierName(Diagnostics.Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces); + if (nodeIsMissing(name)) { + return undefined; + } return finishNode(factory.createTypeParameterDeclaration(name, /*constraint*/ undefined, /*defaultType*/ undefined), typeParameterPos); } @@ -8051,7 +8054,10 @@ namespace ts { const typeParameters = []; do { skipWhitespace(); - typeParameters.push(parseTemplateTagTypeParameter()); + const node = parseTemplateTagTypeParameter(); + if (node !== undefined) { + typeParameters.push(node); + } skipWhitespaceOrAsterisk(); } while (parseOptionalJsdoc(SyntaxKind.CommaToken)); return createNodeArray(typeParameters, pos); diff --git a/src/testRunner/unittests/jsDocParsing.ts b/src/testRunner/unittests/jsDocParsing.ts index f346ca8b02d..c40650bc935 100644 --- a/src/testRunner/unittests/jsDocParsing.ts +++ b/src/testRunner/unittests/jsDocParsing.ts @@ -382,5 +382,9 @@ namespace ts { const root = createSourceFile("foo.ts", "/** */var a = true;", ScriptTarget.ES5, /*setParentNodes*/ false); root.statements[0].getStart(root, /*includeJsdocComment*/ true); }); + describe("missing type parameter in jsDoc doesn't create a 1-element array", () => { + const doc = parseIsolatedJSDocComment("/**\n @template\n*/"); + assert.equal((doc?.jsDoc.tags?.[0] as JSDocTemplateTag).typeParameters.length, 0); + }); }); } diff --git a/tests/baselines/reference/jsdocTemplateTag3.types b/tests/baselines/reference/jsdocTemplateTag3.types index dd44c83de03..216caabdc3c 100644 --- a/tests/baselines/reference/jsdocTemplateTag3.types +++ b/tests/baselines/reference/jsdocTemplateTag3.types @@ -89,7 +89,7 @@ f({ a: 12 }, undefined, undefined, 101, 'nope'); * @param {T} x */ function g(x) { } ->g : <(Missing) extends any, T>(x: T) => void +>g : (x: T) => void >x : T