Use JSDoc @type tag type cast as a contextual type (#18690)

* Use JSDoc `@type` tag type cast as a contextual type

* Suggested changes
This commit is contained in:
Andy 2017-09-22 10:42:02 -07:00 committed by GitHub
parent a4b5870a52
commit 72c8b804da
3 changed files with 22 additions and 11 deletions

View file

@ -13305,8 +13305,11 @@ namespace ts {
case SyntaxKind.TemplateSpan:
Debug.assert(parent.parent.kind === SyntaxKind.TemplateExpression);
return getContextualTypeForSubstitutionExpression(<TemplateExpression>parent.parent, node);
case SyntaxKind.ParenthesizedExpression:
return getContextualType(<ParenthesizedExpression>parent);
case SyntaxKind.ParenthesizedExpression: {
// Like in `checkParenthesizedExpression`, an `/** @type {xyz} */` comment before a parenthesized expression acts as a type cast.
const tag = isInJavaScriptFile(parent) ? getJSDocTypeTag(parent) : undefined;
return tag ? getTypeFromTypeNode(tag.typeExpression.type) : getContextualType(<ParenthesizedExpression>parent);
}
case SyntaxKind.JsxExpression:
return getContextualTypeForJsxExpression(<JsxExpression>parent);
case SyntaxKind.JsxAttribute:
@ -18127,13 +18130,9 @@ namespace ts {
}
function checkParenthesizedExpression(node: ParenthesizedExpression, checkMode?: CheckMode): Type {
if (isInJavaScriptFile(node) && node.jsDoc) {
const typecasts = flatMap(node.jsDoc, doc => filter(doc.tags, tag => tag.kind === SyntaxKind.JSDocTypeTag && !!(tag as JSDocTypeTag).typeExpression && !!(tag as JSDocTypeTag).typeExpression.type));
if (typecasts && typecasts.length) {
// We should have already issued an error if there were multiple type jsdocs
const cast = typecasts[0] as JSDocTypeTag;
return checkAssertionWorker(cast, cast.typeExpression.type, node.expression, checkMode);
}
const tag = isInJavaScriptFile(node) ? getJSDocTypeTag(node) : undefined;
if (tag) {
return checkAssertionWorker(tag, tag.typeExpression.type, node.expression, checkMode);
}
return checkExpression(node.expression, checkMode);
}

View file

@ -4091,9 +4091,14 @@ namespace ts {
return getFirstJSDocTag(node, SyntaxKind.JSDocTemplateTag) as JSDocTemplateTag;
}
/** Gets the JSDoc type tag for the node if present */
/** Gets the JSDoc type tag for the node if present and valid */
export function getJSDocTypeTag(node: Node): JSDocTypeTag | undefined {
return getFirstJSDocTag(node, SyntaxKind.JSDocTypeTag) as JSDocTypeTag;
// We should have already issued an error if there were multiple type jsdocs, so just use the first one.
const tag = getFirstJSDocTag(node, SyntaxKind.JSDocTypeTag) as JSDocTypeTag;
if (tag && tag.typeExpression && tag.typeExpression.type) {
return tag;
}
return undefined;
}
/**

View file

@ -0,0 +1,7 @@
/// <reference path="fourslash.ts" />
// @allowJs: true
// @Filename: /a.js
////const x = /** @type {{ s: string }} */ ({ /**/ });
verify.completionsAt("", ["s", "x"]);