Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8128,6 +8128,10 @@ namespace ts {
// TODO: GH#18217 (should the `|| assignedType` be at a lower precedence?)
return (referenceType && assignedType ? getIntersectionType([assignedType, referenceType]) : referenceType || assignedType)!;
}
const enumTag = getJSDocEnumTag(symbol.valueDeclaration);
if (enumTag && enumTag.typeExpression) {
return getTypeFromTypeNode(enumTag.typeExpression);
}
}

function getTypeReferenceTypeWorker(node: NodeWithTypeArguments, symbol: Symbol, typeArguments: Type[] | undefined): Type | undefined {
Expand Down Expand Up @@ -16563,7 +16567,8 @@ namespace ts {
const contextualTypeHasPattern = contextualType && contextualType.pattern &&
(contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression);
const isInJSFile = isInJavaScriptFile(node) && !isInJsonFile(node);
const isJSObjectLiteral = !contextualType && isInJSFile;
const enumTag = getJSDocEnumTag(node);
const isJSObjectLiteral = !contextualType && isInJSFile && !enumTag;
let typeFlags: TypeFlags = 0;
let patternWithComputedProperties = false;
let hasComputedStringProperty = false;
Expand All @@ -16588,6 +16593,9 @@ namespace ts {
checkTypeAssignableTo(type, jsDocType, memberDecl);
type = jsDocType;
}
else if (enumTag && enumTag.typeExpression) {
checkTypeAssignableTo(type, getTypeFromTypeNode(enumTag.typeExpression), memberDecl);
}
}
typeFlags |= type.flags;
const nameType = computedNameType && computedNameType.flags & TypeFlags.StringOrNumberLiteralOrUnique ?
Expand Down Expand Up @@ -16622,6 +16630,7 @@ namespace ts {
symbolToString(member), typeToString(contextualType!));
}
}

prop.declarations = member.declarations;
prop.parent = member.parent;
if (member.valueDeclaration) {
Expand Down
14 changes: 14 additions & 0 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,8 @@ namespace ts {
visitNode(cbNode, (node as JSDocCallbackTag).typeExpression);
case SyntaxKind.JSDocThisTag:
return visitNode(cbNode, (node as JSDocThisTag).typeExpression);
case SyntaxKind.JSDocEnumTag:
return visitNode(cbNode, (node as JSDocEnumTag).typeExpression);
case SyntaxKind.JSDocSignature:
return visitNodes(cbNode, cbNodes, node.decorators) ||
visitNodes(cbNode, cbNodes, node.modifiers) ||
Expand Down Expand Up @@ -6527,6 +6529,9 @@ namespace ts {
case "this":
tag = parseThisTag(atToken, tagName);
break;
case "enum":
tag = parseEnumTag(atToken, tagName);
break;
case "arg":
case "argument":
case "param":
Expand Down Expand Up @@ -6817,6 +6822,15 @@ namespace ts {
return finishNode(tag);
}

function parseEnumTag(atToken: AtToken, tagName: Identifier): JSDocEnumTag {
const tag = <JSDocEnumTag>createNode(SyntaxKind.JSDocEnumTag, atToken.pos);
tag.atToken = atToken;
tag.tagName = tagName;
tag.typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true);
skipWhitespace();
return finishNode(tag);
}

function parseTypedefTag(atToken: AtToken, tagName: Identifier, indent: number): JSDocTypedefTag {
const typeExpression = tryParseTypeExpression();
skipWhitespace();
Expand Down
9 changes: 8 additions & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ namespace ts {
JSDocAugmentsTag,
JSDocClassTag,
JSDocCallbackTag,
JSDocEnumTag,
JSDocParameterTag,
JSDocReturnTag,
JSDocThisTag,
Expand Down Expand Up @@ -581,6 +582,7 @@ namespace ts {
| FunctionTypeNode
| ConstructorTypeNode
| JSDocFunctionType
| ExportDeclaration
| EndOfFileToken;

export type HasType =
Expand Down Expand Up @@ -2202,7 +2204,7 @@ namespace ts {
name: Identifier;
}

export interface ExportDeclaration extends DeclarationStatement {
export interface ExportDeclaration extends DeclarationStatement, JSDocContainer {
kind: SyntaxKind.ExportDeclaration;
parent: SourceFile | ModuleBlock;
/** Will not be assigned in the case of `export * from "foo";` */
Expand Down Expand Up @@ -2348,6 +2350,11 @@ namespace ts {
kind: SyntaxKind.JSDocClassTag;
}

export interface JSDocEnumTag extends JSDocTag {
kind: SyntaxKind.JSDocEnumTag;
typeExpression?: JSDocTypeExpression;
}

export interface JSDocThisTag extends JSDocTag {
kind: SyntaxKind.JSDocThisTag;
typeExpression?: JSDocTypeExpression;
Expand Down
9 changes: 9 additions & 0 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4985,6 +4985,11 @@ namespace ts {
return getFirstJSDocTag(node, isJSDocClassTag);
}

/** Gets the JSDoc enum tag for the node if present */
export function getJSDocEnumTag(node: Node): JSDocEnumTag | undefined {
return getFirstJSDocTag(node, isJSDocEnumTag);
}

/** Gets the JSDoc this tag for the node if present */
export function getJSDocThisTag(node: Node): JSDocThisTag | undefined {
return getFirstJSDocTag(node, isJSDocThisTag);
Expand Down Expand Up @@ -5749,6 +5754,10 @@ namespace ts {
return node.kind === SyntaxKind.JSDocClassTag;
}

export function isJSDocEnumTag(node: Node): node is JSDocEnumTag {
return node.kind === SyntaxKind.JSDocEnumTag;
}

export function isJSDocThisTag(node: Node): node is JSDocThisTag {
return node.kind === SyntaxKind.JSDocThisTag;
}
Expand Down
44 changes: 26 additions & 18 deletions tests/baselines/reference/api/tsserverlibrary.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -368,20 +368,21 @@ declare namespace ts {
JSDocAugmentsTag = 293,
JSDocClassTag = 294,
JSDocCallbackTag = 295,
JSDocParameterTag = 296,
JSDocReturnTag = 297,
JSDocThisTag = 298,
JSDocTypeTag = 299,
JSDocTemplateTag = 300,
JSDocTypedefTag = 301,
JSDocPropertyTag = 302,
SyntaxList = 303,
NotEmittedStatement = 304,
PartiallyEmittedExpression = 305,
CommaListExpression = 306,
MergeDeclarationMarker = 307,
EndOfDeclarationMarker = 308,
Count = 309,
JSDocEnumTag = 296,
JSDocParameterTag = 297,
JSDocReturnTag = 298,
JSDocThisTag = 299,
JSDocTypeTag = 300,
JSDocTemplateTag = 301,
JSDocTypedefTag = 302,
JSDocPropertyTag = 303,
SyntaxList = 304,
NotEmittedStatement = 305,
PartiallyEmittedExpression = 306,
CommaListExpression = 307,
MergeDeclarationMarker = 308,
EndOfDeclarationMarker = 309,
Count = 310,
FirstAssignment = 58,
LastAssignment = 70,
FirstCompoundAssignment = 59,
Expand All @@ -408,9 +409,9 @@ declare namespace ts {
LastBinaryOperator = 70,
FirstNode = 146,
FirstJSDocNode = 281,
LastJSDocNode = 302,
LastJSDocNode = 303,
FirstJSDocTagNode = 292,
LastJSDocTagNode = 302
LastJSDocTagNode = 303
}
enum NodeFlags {
None = 0,
Expand Down Expand Up @@ -479,7 +480,7 @@ declare namespace ts {
}
interface JSDocContainer {
}
type HasJSDoc = ParameterDeclaration | CallSignatureDeclaration | ConstructSignatureDeclaration | MethodSignature | PropertySignature | ArrowFunction | ParenthesizedExpression | SpreadAssignment | ShorthandPropertyAssignment | PropertyAssignment | FunctionExpression | LabeledStatement | ExpressionStatement | VariableStatement | FunctionDeclaration | ConstructorDeclaration | MethodDeclaration | PropertyDeclaration | AccessorDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumMember | EnumDeclaration | ModuleDeclaration | ImportEqualsDeclaration | IndexSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | JSDocFunctionType | EndOfFileToken;
type HasJSDoc = ParameterDeclaration | CallSignatureDeclaration | ConstructSignatureDeclaration | MethodSignature | PropertySignature | ArrowFunction | ParenthesizedExpression | SpreadAssignment | ShorthandPropertyAssignment | PropertyAssignment | FunctionExpression | LabeledStatement | ExpressionStatement | VariableStatement | FunctionDeclaration | ConstructorDeclaration | MethodDeclaration | PropertyDeclaration | AccessorDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumMember | EnumDeclaration | ModuleDeclaration | ImportEqualsDeclaration | IndexSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | JSDocFunctionType | ExportDeclaration | EndOfFileToken;
type HasType = SignatureDeclaration | VariableDeclaration | ParameterDeclaration | PropertySignature | PropertyDeclaration | TypePredicateNode | ParenthesizedTypeNode | TypeOperatorNode | MappedTypeNode | AssertionExpression | TypeAliasDeclaration | JSDocTypeExpression | JSDocNonNullableType | JSDocNullableType | JSDocOptionalType | JSDocVariadicType;
type HasInitializer = HasExpressionInitializer | ForStatement | ForInStatement | ForOfStatement | JsxAttribute;
type HasExpressionInitializer = VariableDeclaration | ParameterDeclaration | BindingElement | PropertySignature | PropertyDeclaration | PropertyAssignment | EnumMember;
Expand Down Expand Up @@ -1437,7 +1438,7 @@ declare namespace ts {
kind: SyntaxKind.NamespaceExportDeclaration;
name: Identifier;
}
interface ExportDeclaration extends DeclarationStatement {
interface ExportDeclaration extends DeclarationStatement, JSDocContainer {
kind: SyntaxKind.ExportDeclaration;
parent: SourceFile | ModuleBlock;
/** Will not be assigned in the case of `export * from "foo";` */
Expand Down Expand Up @@ -1556,6 +1557,10 @@ declare namespace ts {
interface JSDocClassTag extends JSDocTag {
kind: SyntaxKind.JSDocClassTag;
}
interface JSDocEnumTag extends JSDocTag {
kind: SyntaxKind.JSDocEnumTag;
typeExpression?: JSDocTypeExpression;
}
interface JSDocThisTag extends JSDocTag {
kind: SyntaxKind.JSDocThisTag;
typeExpression?: JSDocTypeExpression;
Expand Down Expand Up @@ -3220,6 +3225,8 @@ declare namespace ts {
function getJSDocAugmentsTag(node: Node): JSDocAugmentsTag | undefined;
/** Gets the JSDoc class tag for the node if present */
function getJSDocClassTag(node: Node): JSDocClassTag | undefined;
/** Gets the JSDoc enum tag for the node if present */
function getJSDocEnumTag(node: Node): JSDocEnumTag | undefined;
/** Gets the JSDoc this tag for the node if present */
function getJSDocThisTag(node: Node): JSDocThisTag | undefined;
/** Gets the JSDoc return tag for the node if present */
Expand Down Expand Up @@ -3412,6 +3419,7 @@ declare namespace ts {
function isJSDoc(node: Node): node is JSDoc;
function isJSDocAugmentsTag(node: Node): node is JSDocAugmentsTag;
function isJSDocClassTag(node: Node): node is JSDocClassTag;
function isJSDocEnumTag(node: Node): node is JSDocEnumTag;
function isJSDocThisTag(node: Node): node is JSDocThisTag;
function isJSDocParameterTag(node: Node): node is JSDocParameterTag;
function isJSDocReturnTag(node: Node): node is JSDocReturnTag;
Expand Down
44 changes: 26 additions & 18 deletions tests/baselines/reference/api/typescript.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -368,20 +368,21 @@ declare namespace ts {
JSDocAugmentsTag = 293,
JSDocClassTag = 294,
JSDocCallbackTag = 295,
JSDocParameterTag = 296,
JSDocReturnTag = 297,
JSDocThisTag = 298,
JSDocTypeTag = 299,
JSDocTemplateTag = 300,
JSDocTypedefTag = 301,
JSDocPropertyTag = 302,
SyntaxList = 303,
NotEmittedStatement = 304,
PartiallyEmittedExpression = 305,
CommaListExpression = 306,
MergeDeclarationMarker = 307,
EndOfDeclarationMarker = 308,
Count = 309,
JSDocEnumTag = 296,
JSDocParameterTag = 297,
JSDocReturnTag = 298,
JSDocThisTag = 299,
JSDocTypeTag = 300,
JSDocTemplateTag = 301,
JSDocTypedefTag = 302,
JSDocPropertyTag = 303,
SyntaxList = 304,
NotEmittedStatement = 305,
PartiallyEmittedExpression = 306,
CommaListExpression = 307,
MergeDeclarationMarker = 308,
EndOfDeclarationMarker = 309,
Count = 310,
FirstAssignment = 58,
LastAssignment = 70,
FirstCompoundAssignment = 59,
Expand All @@ -408,9 +409,9 @@ declare namespace ts {
LastBinaryOperator = 70,
FirstNode = 146,
FirstJSDocNode = 281,
LastJSDocNode = 302,
LastJSDocNode = 303,
FirstJSDocTagNode = 292,
LastJSDocTagNode = 302
LastJSDocTagNode = 303
}
enum NodeFlags {
None = 0,
Expand Down Expand Up @@ -479,7 +480,7 @@ declare namespace ts {
}
interface JSDocContainer {
}
type HasJSDoc = ParameterDeclaration | CallSignatureDeclaration | ConstructSignatureDeclaration | MethodSignature | PropertySignature | ArrowFunction | ParenthesizedExpression | SpreadAssignment | ShorthandPropertyAssignment | PropertyAssignment | FunctionExpression | LabeledStatement | ExpressionStatement | VariableStatement | FunctionDeclaration | ConstructorDeclaration | MethodDeclaration | PropertyDeclaration | AccessorDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumMember | EnumDeclaration | ModuleDeclaration | ImportEqualsDeclaration | IndexSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | JSDocFunctionType | EndOfFileToken;
type HasJSDoc = ParameterDeclaration | CallSignatureDeclaration | ConstructSignatureDeclaration | MethodSignature | PropertySignature | ArrowFunction | ParenthesizedExpression | SpreadAssignment | ShorthandPropertyAssignment | PropertyAssignment | FunctionExpression | LabeledStatement | ExpressionStatement | VariableStatement | FunctionDeclaration | ConstructorDeclaration | MethodDeclaration | PropertyDeclaration | AccessorDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumMember | EnumDeclaration | ModuleDeclaration | ImportEqualsDeclaration | IndexSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | JSDocFunctionType | ExportDeclaration | EndOfFileToken;
type HasType = SignatureDeclaration | VariableDeclaration | ParameterDeclaration | PropertySignature | PropertyDeclaration | TypePredicateNode | ParenthesizedTypeNode | TypeOperatorNode | MappedTypeNode | AssertionExpression | TypeAliasDeclaration | JSDocTypeExpression | JSDocNonNullableType | JSDocNullableType | JSDocOptionalType | JSDocVariadicType;
type HasInitializer = HasExpressionInitializer | ForStatement | ForInStatement | ForOfStatement | JsxAttribute;
type HasExpressionInitializer = VariableDeclaration | ParameterDeclaration | BindingElement | PropertySignature | PropertyDeclaration | PropertyAssignment | EnumMember;
Expand Down Expand Up @@ -1437,7 +1438,7 @@ declare namespace ts {
kind: SyntaxKind.NamespaceExportDeclaration;
name: Identifier;
}
interface ExportDeclaration extends DeclarationStatement {
interface ExportDeclaration extends DeclarationStatement, JSDocContainer {
kind: SyntaxKind.ExportDeclaration;
parent: SourceFile | ModuleBlock;
/** Will not be assigned in the case of `export * from "foo";` */
Expand Down Expand Up @@ -1556,6 +1557,10 @@ declare namespace ts {
interface JSDocClassTag extends JSDocTag {
kind: SyntaxKind.JSDocClassTag;
}
interface JSDocEnumTag extends JSDocTag {
kind: SyntaxKind.JSDocEnumTag;
typeExpression?: JSDocTypeExpression;
}
interface JSDocThisTag extends JSDocTag {
kind: SyntaxKind.JSDocThisTag;
typeExpression?: JSDocTypeExpression;
Expand Down Expand Up @@ -3220,6 +3225,8 @@ declare namespace ts {
function getJSDocAugmentsTag(node: Node): JSDocAugmentsTag | undefined;
/** Gets the JSDoc class tag for the node if present */
function getJSDocClassTag(node: Node): JSDocClassTag | undefined;
/** Gets the JSDoc enum tag for the node if present */
function getJSDocEnumTag(node: Node): JSDocEnumTag | undefined;
/** Gets the JSDoc this tag for the node if present */
function getJSDocThisTag(node: Node): JSDocThisTag | undefined;
/** Gets the JSDoc return tag for the node if present */
Expand Down Expand Up @@ -3412,6 +3419,7 @@ declare namespace ts {
function isJSDoc(node: Node): node is JSDoc;
function isJSDocAugmentsTag(node: Node): node is JSDocAugmentsTag;
function isJSDocClassTag(node: Node): node is JSDocClassTag;
function isJSDocEnumTag(node: Node): node is JSDocEnumTag;
function isJSDocThisTag(node: Node): node is JSDocThisTag;
function isJSDocParameterTag(node: Node): node is JSDocParameterTag;
function isJSDocReturnTag(node: Node): node is JSDocReturnTag;
Expand Down
65 changes: 65 additions & 0 deletions tests/baselines/reference/enumTag.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
tests/cases/conformance/jsdoc/a.js(6,5): error TS2322: Type 'number' is not assignable to type 'string'.
tests/cases/conformance/jsdoc/a.js(12,5): error TS2322: Type 'string' is not assignable to type 'number'.
tests/cases/conformance/jsdoc/a.js(37,16): error TS2339: Property 'UNKNOWN' does not exist on type '{ START: string; MIDDLE: string; END: string; MISTAKE: number; OK_I_GUESS: number; }'.


==== tests/cases/conformance/jsdoc/a.js (3 errors) ====
/** @enum {string} */
const Target = {
START: "start",
MIDDLE: "middle",
END: "end",
MISTAKE: 1,
~~~~~~~~~~
!!! error TS2322: Type 'number' is not assignable to type 'string'.
/** @type {number} */
OK_I_GUESS: 2
}
/** @enum {number} */
const Second = {
MISTAKE: "end",
~~~~~~~~~~~~~~
!!! error TS2322: Type 'string' is not assignable to type 'number'.
OK: 1,
/** @type {number} */
FINE: 2,
}
/** @enum {function(number): number} */
const Fs = {
ADD1: n => n + 1,
ID: n => n,
SUB1: n => n - 1
}

/** @param {Target} t
* @param {Second} s
* @param {Fs} f
*/
function consume(t,s,f) {
/** @type {string} */
var str = t
/** @type {number} */
var num = s
/** @type {(n: number) => number} */
var fun = f
/** @type {Target} */
var v = Target.START
v = Target.UNKNOWN // error, can't find 'UNKNOWN'
~~~~~~~
!!! error TS2339: Property 'UNKNOWN' does not exist on type '{ START: string; MIDDLE: string; END: string; MISTAKE: number; OK_I_GUESS: number; }'.
v = Second.MISTAKE // meh..ok, I guess?
v = 'something else' // allowed, like Typescript's classic enums and unlike its string enums
}
/** @param {string} s */
function ff(s) {
// element access with arbitrary string is an error only with noImplicitAny
if (!Target[s]) {
return null
}
else {
return Target[s]
}
}



Loading