diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index c5cbb950f69d7..8f7ea52ebe94b 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2701,19 +2701,10 @@ namespace ts { return finishNode(factory.createThisTypeNode(), pos); } - function parseJSDocAllType(postFixEquals: boolean): JSDocAllType | JSDocOptionalType { + function parseJSDocAllType(): JSDocAllType | JSDocOptionalType { const pos = getNodePos(); nextToken(); - - const node = factory.createJSDocAllType(); - if (postFixEquals) { - // Trim the trailing `=` from the `*=` token - const end = Math.max(getNodePos() - 1, pos); - return finishNode(factory.createJSDocOptionalType(finishNode(node, pos, end)), pos); - } - else { - return finishNode(node, pos); - } + return finishNode(factory.createJSDocAllType(), pos); } function parseJSDocNonNullableType(): TypeNode { @@ -3396,12 +3387,14 @@ namespace ts { case SyntaxKind.ObjectKeyword: // If these are followed by a dot, then parse these out as a dotted type reference instead. return tryParse(parseKeywordAndNoDot) || parseTypeReference(); - case SyntaxKind.AsteriskToken: - return parseJSDocAllType(/*postfixEquals*/ false); case SyntaxKind.AsteriskEqualsToken: - return parseJSDocAllType(/*postfixEquals*/ true); + // If there is '*=', treat it as * followed by postfix = + scanner.reScanAsteriskEqualsToken(); + // falls through + case SyntaxKind.AsteriskToken: + return parseJSDocAllType(); case SyntaxKind.QuestionQuestionToken: - // If there is '??', consider that is prefix '?' in JSDoc type. + // If there is '??', treat it as prefix-'?' in JSDoc type. scanner.reScanQuestionToken(); // falls through case SyntaxKind.QuestionToken: diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index b58ae9aee773c..0a4e5126987eb 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -34,6 +34,7 @@ namespace ts { getTokenFlags(): TokenFlags; reScanGreaterToken(): SyntaxKind; reScanSlashToken(): SyntaxKind; + reScanAsteriskEqualsToken(): SyntaxKind; reScanTemplateToken(isTaggedTemplate: boolean): SyntaxKind; reScanTemplateHeadOrNoSubstitutionTemplate(): SyntaxKind; scanJsxIdentifier(): SyntaxKind; @@ -954,6 +955,7 @@ namespace ts { getNumericLiteralFlags: () => tokenFlags & TokenFlags.NumericLiteralFlags, getTokenFlags: () => tokenFlags, reScanGreaterToken, + reScanAsteriskEqualsToken, reScanSlashToken, reScanTemplateToken, reScanTemplateHeadOrNoSubstitutionTemplate, @@ -2086,6 +2088,12 @@ namespace ts { return token; } + function reScanAsteriskEqualsToken(): SyntaxKind { + Debug.assert(token === SyntaxKind.AsteriskEqualsToken, "'reScanAsteriskEqualsToken' should only be called on a '*='"); + pos = tokenPos + 1; + return token = SyntaxKind.EqualsToken; + } + function reScanSlashToken(): SyntaxKind { if (token === SyntaxKind.SlashToken || token === SyntaxKind.SlashEqualsToken) { let p = tokenPos + 1; diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 360aa0650053d..83b03093da4b0 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -3902,6 +3902,7 @@ declare namespace ts { isUnterminated(): boolean; reScanGreaterToken(): SyntaxKind; reScanSlashToken(): SyntaxKind; + reScanAsteriskEqualsToken(): SyntaxKind; reScanTemplateToken(isTaggedTemplate: boolean): SyntaxKind; reScanTemplateHeadOrNoSubstitutionTemplate(): SyntaxKind; scanJsxIdentifier(): SyntaxKind; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index d30b0b8f7ac84..e85e4a8bf70b2 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -3902,6 +3902,7 @@ declare namespace ts { isUnterminated(): boolean; reScanGreaterToken(): SyntaxKind; reScanSlashToken(): SyntaxKind; + reScanAsteriskEqualsToken(): SyntaxKind; reScanTemplateToken(isTaggedTemplate: boolean): SyntaxKind; reScanTemplateHeadOrNoSubstitutionTemplate(): SyntaxKind; scanJsxIdentifier(): SyntaxKind; diff --git a/tests/baselines/reference/jsdocParseStarEquals.symbols b/tests/baselines/reference/jsdocParseStarEquals.symbols index a882cf23eb21c..795d97f20b853 100644 --- a/tests/baselines/reference/jsdocParseStarEquals.symbols +++ b/tests/baselines/reference/jsdocParseStarEquals.symbols @@ -12,3 +12,10 @@ function f(...args) { var x; >x : Symbol(x, Decl(a.js, 7, 3)) + +/** @param {function():*=} f */ +function cbf(f) { +>cbf : Symbol(cbf, Decl(a.js, 7, 6)) +>f : Symbol(f, Decl(a.js, 11, 13)) +} + diff --git a/tests/baselines/reference/jsdocParseStarEquals.types b/tests/baselines/reference/jsdocParseStarEquals.types index 1142fb05daea3..174e543dd7d92 100644 --- a/tests/baselines/reference/jsdocParseStarEquals.types +++ b/tests/baselines/reference/jsdocParseStarEquals.types @@ -2,8 +2,8 @@ /** @param {...*=} args @return {*=} */ function f(...args) { ->f : (...args: (any | undefined)[]) => any | undefined ->args : any[] +>f : (...args?: any[] | undefined) => any | undefined +>args : any return null >null : null @@ -13,3 +13,10 @@ function f(...args) { var x; >x : any + +/** @param {function():*=} f */ +function cbf(f) { +>cbf : (f?: (() => any) | undefined) => void +>f : (() => any) | undefined +} + diff --git a/tests/cases/conformance/jsdoc/jsdocParseStarEquals.ts b/tests/cases/conformance/jsdoc/jsdocParseStarEquals.ts index e5f07bb3d2f6d..ef93965e0fc87 100644 --- a/tests/cases/conformance/jsdoc/jsdocParseStarEquals.ts +++ b/tests/cases/conformance/jsdoc/jsdocParseStarEquals.ts @@ -12,3 +12,8 @@ function f(...args) { /** @type *= */ var x; + + +/** @param {function():*=} f */ +function cbf(f) { +}