diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index ec3e815758..d55f3650c1 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -2179,7 +2179,7 @@ namespace ts { return bindPropertyWorker(node as JSDocRecordMember); case SyntaxKind.JSDocPropertyTag: return declareSymbolAndAddToSymbolTable(node as JSDocPropertyTag, - (node as JSDocPropertyTag).typeExpression && (node as JSDocPropertyTag).typeExpression.type.kind === SyntaxKind.JSDocOptionalType ? + (node as JSDocPropertyTag).isBracketed || ((node as JSDocPropertyTag).typeExpression && (node as JSDocPropertyTag).typeExpression.type.kind === SyntaxKind.JSDocOptionalType) ? SymbolFlags.Property | SymbolFlags.Optional : SymbolFlags.Property, SymbolFlags.PropertyExcludes); case SyntaxKind.JSDocFunctionType: diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 04209ab092..07d4a9ada4 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -6631,10 +6631,7 @@ namespace ts { }); } - function parseParamTag(atToken: AtToken, tagName: Identifier) { - let typeExpression = tryParseTypeExpression(); - skipWhitespace(); - + function parseBracketNameInPropertyAndParamTag() { let name: Identifier; let isBracketed: boolean; // Looking for something like '[foo]' or 'foo' @@ -6653,6 +6650,14 @@ namespace ts { else if (tokenIsIdentifierOrKeyword(token())) { name = parseJSDocIdentifierName(); } + return { name, isBracketed }; + } + + function parseParamTag(atToken: AtToken, tagName: Identifier) { + let typeExpression = tryParseTypeExpression(); + skipWhitespace(); + + const { name, isBracketed } = parseBracketNameInPropertyAndParamTag(); if (!name) { parseErrorAtPosition(scanner.getStartPos(), 0, Diagnostics.Identifier_expected); @@ -6709,8 +6714,9 @@ namespace ts { function parsePropertyTag(atToken: AtToken, tagName: Identifier): JSDocPropertyTag { const typeExpression = tryParseTypeExpression(); skipWhitespace(); - const name = parseJSDocIdentifierName(); + const { name, isBracketed } = parseBracketNameInPropertyAndParamTag(); skipWhitespace(); + if (!name) { parseErrorAtPosition(scanner.getStartPos(), /*length*/ 0, Diagnostics.Identifier_expected); return undefined; @@ -6721,6 +6727,7 @@ namespace ts { result.tagName = tagName; result.name = name; result.typeExpression = typeExpression; + result.isBracketed = isBracketed; return finishNode(result); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c295a4c956..cc71bd7b42 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2146,6 +2146,7 @@ namespace ts { kind: SyntaxKind.JSDocPropertyTag; name: Identifier; typeExpression: JSDocTypeExpression; + isBracketed: boolean; } export interface JSDocTypeLiteral extends JSDocType { diff --git a/tests/baselines/reference/checkJsdocTypedefInParamTag1.js b/tests/baselines/reference/checkJsdocTypedefInParamTag1.js index 28d6a96b3f..d4983bfd58 100644 --- a/tests/baselines/reference/checkJsdocTypedefInParamTag1.js +++ b/tests/baselines/reference/checkJsdocTypedefInParamTag1.js @@ -4,6 +4,8 @@ * @typedef {Object} Opts * @property {string} x * @property {string=} y + * @property {string} [z] + * @property {string} [w="hi"] * * @param {Opts} opts */ @@ -17,6 +19,8 @@ foo({x: 'abc'}); * @typedef {Object} Opts * @property {string} x * @property {string=} y + * @property {string} [z] + * @property {string} [w="hi"] * * @param {Opts} opts */ diff --git a/tests/baselines/reference/checkJsdocTypedefInParamTag1.symbols b/tests/baselines/reference/checkJsdocTypedefInParamTag1.symbols index 19672d6e52..cd2455797b 100644 --- a/tests/baselines/reference/checkJsdocTypedefInParamTag1.symbols +++ b/tests/baselines/reference/checkJsdocTypedefInParamTag1.symbols @@ -4,14 +4,16 @@ * @typedef {Object} Opts * @property {string} x * @property {string=} y + * @property {string} [z] + * @property {string} [w="hi"] * * @param {Opts} opts */ function foo(opts) {} >foo : Symbol(foo, Decl(0.js, 0, 0)) ->opts : Symbol(opts, Decl(0.js, 8, 13)) +>opts : Symbol(opts, Decl(0.js, 10, 13)) foo({x: 'abc'}); >foo : Symbol(foo, Decl(0.js, 0, 0)) ->x : Symbol(x, Decl(0.js, 10, 5)) +>x : Symbol(x, Decl(0.js, 12, 5)) diff --git a/tests/baselines/reference/checkJsdocTypedefInParamTag1.types b/tests/baselines/reference/checkJsdocTypedefInParamTag1.types index ff30e8da8a..cc923e3303 100644 --- a/tests/baselines/reference/checkJsdocTypedefInParamTag1.types +++ b/tests/baselines/reference/checkJsdocTypedefInParamTag1.types @@ -4,16 +4,18 @@ * @typedef {Object} Opts * @property {string} x * @property {string=} y + * @property {string} [z] + * @property {string} [w="hi"] * * @param {Opts} opts */ function foo(opts) {} ->foo : (opts: { x: string; y?: string; }) => void ->opts : { x: string; y?: string; } +>foo : (opts: { x: string; y?: string; z?: string; w?: string; }) => void +>opts : { x: string; y?: string; z?: string; w?: string; } foo({x: 'abc'}); >foo({x: 'abc'}) : void ->foo : (opts: { x: string; y?: string; }) => void +>foo : (opts: { x: string; y?: string; z?: string; w?: string; }) => void >{x: 'abc'} : { x: string; } >x : string >'abc' : "abc" diff --git a/tests/cases/conformance/jsdoc/checkJsdocTypedefInParamTag1.ts b/tests/cases/conformance/jsdoc/checkJsdocTypedefInParamTag1.ts index 261ce070cf..80ca21bd4f 100644 --- a/tests/cases/conformance/jsdoc/checkJsdocTypedefInParamTag1.ts +++ b/tests/cases/conformance/jsdoc/checkJsdocTypedefInParamTag1.ts @@ -7,6 +7,8 @@ * @typedef {Object} Opts * @property {string} x * @property {string=} y + * @property {string} [z] + * @property {string} [w="hi"] * * @param {Opts} opts */