diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6da456afcbc..321bfcc74a3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5326,6 +5326,8 @@ namespace ts { return getTypeFromThisTypeNode(node); case SyntaxKind.StringLiteralType: return getTypeFromStringLiteralTypeNode(node); + case SyntaxKind.JSDocStringLiteralType: + return getTypeFromStringLiteralTypeNode((node).stringLiteral); case SyntaxKind.TypeReference: case SyntaxKind.JSDocTypeReference: return getTypeFromTypeReference(node); diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 774cea60e09..2e76093cde2 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -5860,9 +5860,10 @@ namespace ts { case SyntaxKind.SymbolKeyword: case SyntaxKind.VoidKeyword: return parseTokenNode(); + case SyntaxKind.StringLiteral: + return parseJSDocStringLiteralType(); } - // TODO (drosen): Parse string literal types in JSDoc as well. return parseJSDocTypeReference(); } @@ -6041,6 +6042,12 @@ namespace ts { return finishNode(result); } + function parseJSDocStringLiteralType(): JSDocStringLiteralType { + const result = createNode(SyntaxKind.JSDocStringLiteralType); + result.stringLiteral = parseStringLiteralTypeNode(); + return finishNode(result); + } + function parseJSDocUnknownOrNullableType(): JSDocUnknownType | JSDocNullableType { const pos = scanner.getStartPos(); // skip the ? diff --git a/src/compiler/types.ts b/src/compiler/types.ts index dc332b24567..17e8a25038d 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -346,6 +346,7 @@ namespace ts { JSDocTypedefTag, JSDocPropertyTag, JSDocTypeLiteral, + JSDocStringLiteralType, // Synthesized list SyntaxList, @@ -1491,6 +1492,10 @@ namespace ts { type: JSDocType; } + export interface JSDocStringLiteralType extends JSDocType { + stringLiteral: StringLiteralTypeNode; + } + export type JSDocTypeReferencingNode = JSDocThisType | JSDocConstructorType | JSDocVariadicType | JSDocOptionalType | JSDocNullableType | JSDocNonNullableType; // @kind(SyntaxKind.JSDocRecordMember) diff --git a/tests/baselines/reference/jsdocStringLiteral.js b/tests/baselines/reference/jsdocStringLiteral.js new file mode 100644 index 00000000000..f74faf3519e --- /dev/null +++ b/tests/baselines/reference/jsdocStringLiteral.js @@ -0,0 +1,16 @@ +//// [in.js] +/** + * @param {'literal'} input + */ +function f(input) { + return input + '.'; +} + + +//// [out.js] +/** + * @param {'literal'} input + */ +function f(input) { + return input + '.'; +} diff --git a/tests/baselines/reference/jsdocStringLiteral.symbols b/tests/baselines/reference/jsdocStringLiteral.symbols new file mode 100644 index 00000000000..0414efc24d9 --- /dev/null +++ b/tests/baselines/reference/jsdocStringLiteral.symbols @@ -0,0 +1,12 @@ +=== tests/cases/compiler/in.js === +/** + * @param {'literal'} input + */ +function f(input) { +>f : Symbol(f, Decl(in.js, 0, 0)) +>input : Symbol(input, Decl(in.js, 3, 11)) + + return input + '.'; +>input : Symbol(input, Decl(in.js, 3, 11)) +} + diff --git a/tests/baselines/reference/jsdocStringLiteral.types b/tests/baselines/reference/jsdocStringLiteral.types new file mode 100644 index 00000000000..c7b87857d18 --- /dev/null +++ b/tests/baselines/reference/jsdocStringLiteral.types @@ -0,0 +1,14 @@ +=== tests/cases/compiler/in.js === +/** + * @param {'literal'} input + */ +function f(input) { +>f : (input: "literal") => string +>input : "literal" + + return input + '.'; +>input + '.' : string +>input : "literal" +>'.' : string +} + diff --git a/tests/cases/conformance/jsdoc/jsdocStringLiteral.ts b/tests/cases/conformance/jsdoc/jsdocStringLiteral.ts new file mode 100644 index 00000000000..d2a0d6c644d --- /dev/null +++ b/tests/cases/conformance/jsdoc/jsdocStringLiteral.ts @@ -0,0 +1,12 @@ +// @allowJs: true +// @filename: in.js +// @out: out.js +/** + * @param {'literal'} p1 + * @param {"literal"} p2 + * @param {'literal' | 'other'} p3 + * @param {'literal' | number} p4 + */ +function f(p1, p2, p3, p4) { + return p1 + p2 + p3 + p4 + '.'; +}