Handle @typedef tag with missing type (#18662)

* Handle @typedef tag with missing type

* Add single quotes to diagnostic

* Remove redundant jsdoc checking (now done on every source element)

* Update baselines
This commit is contained in:
Andy 2017-09-25 12:11:33 -07:00 committed by GitHub
parent 5a0c60a9a1
commit b4018a2ef1
7 changed files with 110 additions and 6 deletions

View File

@ -5124,7 +5124,9 @@ namespace ts {
const declaration = <JSDocTypedefTag | TypeAliasDeclaration>find(symbol.declarations, d =>
d.kind === SyntaxKind.JSDocTypedefTag || d.kind === SyntaxKind.TypeAliasDeclaration);
let type = getTypeFromTypeNode(declaration.kind === SyntaxKind.JSDocTypedefTag ? declaration.typeExpression : declaration.type);
const typeNode = declaration.kind === SyntaxKind.JSDocTypedefTag ? declaration.typeExpression : declaration.type;
// If typeNode is missing, we will error in checkJSDocTypedefTag.
let type = typeNode ? getTypeFromTypeNode(typeNode) : unknownType;
if (popTypeResolution()) {
const typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
@ -19779,11 +19781,11 @@ namespace ts {
}
}
function checkJSDoc(node: FunctionDeclaration | MethodDeclaration) {
if (!isInJavaScriptFile(node)) {
return;
function checkJSDocTypedefTag(node: JSDocTypedefTag) {
if (!node.typeExpression) {
// If the node had `@property` tags, `typeExpression` would have been set to the first property tag.
error(node.name, Diagnostics.JSDoc_typedef_tag_should_either_have_a_type_annotation_or_be_followed_by_property_or_member_tags);
}
forEach(node.jsDoc, checkSourceElement);
}
function checkJSDocComment(node: JSDoc) {
@ -19795,7 +19797,6 @@ namespace ts {
}
function checkFunctionOrMethodDeclaration(node: FunctionDeclaration | MethodDeclaration): void {
checkJSDoc(node);
checkDecorators(node);
checkSignatureDeclaration(node);
const functionFlags = getFunctionFlags(node);
@ -22429,6 +22430,12 @@ namespace ts {
return;
}
if (isInJavaScriptFile(node) && (node as JSDocContainer).jsDoc) {
for (const jsdoc of (node as JSDocContainer).jsDoc) {
checkJSDocComment(jsdoc);
}
}
const kind = node.kind;
if (cancellationToken) {
// Only bother checking on a few construct kinds. We don't want to be excessively
@ -22483,6 +22490,8 @@ namespace ts {
case SyntaxKind.ParenthesizedType:
case SyntaxKind.TypeOperator:
return checkSourceElement((<ParenthesizedTypeNode | TypeOperatorNode>node).type);
case SyntaxKind.JSDocTypedefTag:
return checkJSDocTypedefTag(node as JSDocTypedefTag);
case SyntaxKind.JSDocComment:
return checkJSDocComment(node as JSDoc);
case SyntaxKind.JSDocParameterTag:

View File

@ -3507,6 +3507,10 @@
"category": "Error",
"code": 8020
},
"JSDoc '@typedef' tag should either have a type annotation or be followed by '@property' or '@member' tags.": {
"category": "Error",
"code": 8021
},
"Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clause.": {
"category": "Error",
"code": 9002

View File

@ -0,0 +1,23 @@
/a.js(2,14): error TS8021: JSDoc '@typedef' tag should either have a type annotation or be followed by '@property' or '@member' tags.
/a.js(12,11): error TS1005: '{' expected.
==== /a.js (2 errors) ====
// Bad: missing a type
/** @typedef T */
~
!!! error TS8021: JSDoc '@typedef' tag should either have a type annotation or be followed by '@property' or '@member' tags.
const t = 0;
// OK: missing a type, but have property tags.
/**
* @typedef Person
* @property {string} name
*/
/** @type Person */
~~~~~~
!!! error TS1005: '{' expected.
const person = { name: "" };

View File

@ -0,0 +1,18 @@
=== /a.js ===
// Bad: missing a type
/** @typedef T */
const t = 0;
>t : Symbol(t, Decl(a.js, 3, 5))
// OK: missing a type, but have property tags.
/**
* @typedef Person
* @property {string} name
*/
/** @type Person */
const person = { name: "" };
>person : Symbol(person, Decl(a.js, 12, 5))
>name : Symbol(name, Decl(a.js, 12, 16))

View File

@ -0,0 +1,21 @@
=== /a.js ===
// Bad: missing a type
/** @typedef T */
const t = 0;
>t : 0
>0 : 0
// OK: missing a type, but have property tags.
/**
* @typedef Person
* @property {string} name
*/
/** @type Person */
const person = { name: "" };
>person : { [x: string]: any; name: string; }
>{ name: "" } : { [x: string]: any; name: string; }
>name : string
>"" : ""

View File

@ -0,0 +1,18 @@
// @allowJs: true
// @checkJs: true
// @noEmit: true
// @Filename: /a.js
// Bad: missing a type
/** @typedef T */
const t = 0;
// OK: missing a type, but have property tags.
/**
* @typedef Person
* @property {string} name
*/
/** @type Person */
const person = { name: "" };

View File

@ -0,0 +1,11 @@
/// <reference path='fourslash.ts' />
// @allowJs: true
// @Filename: /a.js
/////**
//// * @typedef /**/A
//// */
////var x;
verify.quickInfoAt("", "type A = any");