diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 38a341eaa5a..7ceb09730ff 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -6160,7 +6160,7 @@ namespace ts { parseExpected(SyntaxKind.CloseBracketToken); } - else if (token === SyntaxKind.Identifier) { + else if (token === SyntaxKind.Identifier || isTSOnlyKeyword(token)) { name = parseJSDocIdentifier(); } @@ -6259,7 +6259,7 @@ namespace ts { } function parseJSDocIdentifier(): Identifier { - if (token !== SyntaxKind.Identifier) { + if (token !== SyntaxKind.Identifier && !isTSOnlyKeyword(token)) { parseErrorAtCurrentToken(Diagnostics.Identifier_expected); return undefined; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index b97ad70a74a..eb5c62844c4 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -435,7 +435,7 @@ namespace ts { const { line: startLine } = getLineAndCharacterOfPosition(sourceFile, node.body.pos); const { line: endLine } = getLineAndCharacterOfPosition(sourceFile, node.body.end); if (startLine < endLine) { - // The arrow function spans multiple lines, + // The arrow function spans multiple lines, // make the error span be the first line, inclusive. return createTextSpan(pos, getEndLinePosition(startLine, sourceFile) - pos + 1); } @@ -1301,10 +1301,10 @@ namespace ts { if (node.jsDocComment) { return node.jsDocComment; } - // Try to recognize this pattern when node is initializer of variable declaration and JSDoc comments are on containing variable statement. - // /** + // Try to recognize this pattern when node is initializer of variable declaration and JSDoc comments are on containing variable statement. + // /** // * @param {number} name - // * @returns {number} + // * @returns {number} // */ // var x = function(name) { return name.length; } if (checkParentVariableStatement) { @@ -1667,6 +1667,27 @@ namespace ts { return SyntaxKind.FirstKeyword <= token && token <= SyntaxKind.LastKeyword; } + // Some keywords are TypeScript only, so they should not be parsed as considered as + // keywords in JavaScript + export function isJSKeyword(token: SyntaxKind): boolean { + switch (token) { + case SyntaxKind.TypeKeyword: + case SyntaxKind.AsKeyword: + case SyntaxKind.AnyKeyword: + case SyntaxKind.DeclareKeyword: + case SyntaxKind.IsKeyword: + case SyntaxKind.ReadonlyKeyword: + case SyntaxKind.FromKeyword: + return false; + default: + return isKeyword(token); + } + } + + export function isTSOnlyKeyword(token: SyntaxKind): boolean { + return isKeyword(token) && !isJSKeyword(token); + } + export function isTrivia(token: SyntaxKind) { return SyntaxKind.FirstTriviaToken <= token && token <= SyntaxKind.LastTriviaToken; } diff --git a/tests/cases/fourslash/server/jsdocParamTagSpecialKeywords.ts b/tests/cases/fourslash/server/jsdocParamTagSpecialKeywords.ts new file mode 100644 index 00000000000..be7ca5f0dff --- /dev/null +++ b/tests/cases/fourslash/server/jsdocParamTagSpecialKeywords.ts @@ -0,0 +1,14 @@ +/// + +// @allowNonTsExtensions: true +// @Filename: test.js +//// /** +//// * @param {string} type +//// */ +//// function test(type) { +//// type./**/ +//// } + + +goTo.marker(); +verify.completionListContains("charAt"); \ No newline at end of file