mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-15 12:51:30 -05:00
Get return type from @type tag (#25580)
* Get return type from `@type` tag This only happens in the checker, where the type is easily accessible. The syntax-based check in getEffectiveReturnTypeNode as a fast path, and for other uses that don't want to make a call to getTypeFromTypeNode. Fixes #25525 * Implement PR suggestions * Error when type tag isn't callable * Fix lint
This commit is contained in:
committed by
GitHub
parent
66e9aaac18
commit
bd7b97ce61
@@ -7566,12 +7566,21 @@ namespace ts {
|
||||
const setter = getDeclarationOfKind<AccessorDeclaration>(getSymbolOfNode(declaration), SyntaxKind.SetAccessor);
|
||||
return getAnnotatedAccessorType(setter);
|
||||
}
|
||||
|
||||
const typeFromTag = getReturnTypeOfTypeTag(declaration);
|
||||
if (typeFromTag) {
|
||||
return typeFromTag;
|
||||
}
|
||||
if (nodeIsMissing((<FunctionLikeDeclaration>declaration).body)) {
|
||||
return anyType;
|
||||
}
|
||||
}
|
||||
|
||||
function getReturnTypeOfTypeTag(node: SignatureDeclaration | JSDocSignature) {
|
||||
const typeTag = isInJavaScriptFile(node) ? getJSDocTypeTag(node) : undefined;
|
||||
const signatures = typeTag && typeTag.typeExpression && getSignaturesOfType(getTypeFromTypeNode(typeTag.typeExpression), SignatureKind.Call);
|
||||
return signatures && signatures.length === 1 ? getReturnTypeOfSignature(signatures[0]) : undefined;
|
||||
}
|
||||
|
||||
function containsArgumentsReference(declaration: SignatureDeclaration): boolean {
|
||||
const links = getNodeLinks(declaration);
|
||||
if (links.containsArgumentsReference === undefined) {
|
||||
@@ -20539,15 +20548,20 @@ namespace ts {
|
||||
return type;
|
||||
}
|
||||
|
||||
function getReturnOrPromisedType(node: FunctionLikeDeclaration | MethodSignature, functionFlags: FunctionFlags) {
|
||||
const returnTypeNode = getEffectiveReturnTypeNode(node);
|
||||
return returnTypeNode &&
|
||||
((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async ?
|
||||
checkAsyncFunctionReturnType(node, returnTypeNode) : // Async function
|
||||
getTypeFromTypeNode(returnTypeNode)) || // AsyncGenerator function, Generator function, or normal function
|
||||
getReturnTypeOfTypeTag(node); // type from JSDoc @type tag
|
||||
}
|
||||
|
||||
function checkFunctionExpressionOrObjectLiteralMethodDeferred(node: ArrowFunction | FunctionExpression | MethodDeclaration) {
|
||||
Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node));
|
||||
|
||||
const functionFlags = getFunctionFlags(node);
|
||||
const returnTypeNode = getEffectiveReturnTypeNode(node);
|
||||
const returnOrPromisedType = returnTypeNode &&
|
||||
((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async ?
|
||||
checkAsyncFunctionReturnType(node) : // Async function
|
||||
getTypeFromTypeNode(returnTypeNode)); // AsyncGenerator function, Generator function, or normal function
|
||||
const returnOrPromisedType = getReturnOrPromisedType(node, functionFlags);
|
||||
|
||||
if ((functionFlags & FunctionFlags.Generator) === 0) { // Async function or normal function
|
||||
// return is not necessary in the body of generators
|
||||
@@ -20555,7 +20569,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (node.body) {
|
||||
if (!returnTypeNode) {
|
||||
if (!getEffectiveReturnTypeNode(node)) {
|
||||
// There are some checks that are only performed in getReturnTypeFromBody, that may produce errors
|
||||
// we need. An example is the noImplicitAny errors resulting from widening the return expression
|
||||
// of a function. Because checking of function expression bodies is deferred, there was never an
|
||||
@@ -22007,7 +22021,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
else if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async) {
|
||||
checkAsyncFunctionReturnType(<FunctionLikeDeclaration>node);
|
||||
checkAsyncFunctionReturnType(<FunctionLikeDeclaration>node, returnTypeNode);
|
||||
}
|
||||
}
|
||||
if (node.kind !== SyntaxKind.IndexSignature && node.kind !== SyntaxKind.JSDocFunctionType) {
|
||||
@@ -23067,7 +23081,7 @@ namespace ts {
|
||||
*
|
||||
* @param node The signature to check
|
||||
*/
|
||||
function checkAsyncFunctionReturnType(node: FunctionLikeDeclaration | MethodSignature): Type {
|
||||
function checkAsyncFunctionReturnType(node: FunctionLikeDeclaration | MethodSignature, returnTypeNode: TypeNode): Type {
|
||||
// As part of our emit for an async function, we will need to emit the entity name of
|
||||
// the return type annotation as an expression. To meet the necessary runtime semantics
|
||||
// for __awaiter, we must also check that the type of the declaration (e.g. the static
|
||||
@@ -23092,7 +23106,6 @@ namespace ts {
|
||||
// then<U>(...): Promise<U>;
|
||||
// }
|
||||
//
|
||||
const returnTypeNode = getEffectiveReturnTypeNode(node)!; // TODO: GH#18217
|
||||
const returnType = getTypeFromTypeNode(returnTypeNode);
|
||||
|
||||
if (languageVersion >= ScriptTarget.ES2015) {
|
||||
@@ -23502,15 +23515,12 @@ namespace ts {
|
||||
const body = node.kind === SyntaxKind.MethodSignature ? undefined : node.body;
|
||||
checkSourceElement(body);
|
||||
|
||||
const returnTypeNode = getEffectiveReturnTypeNode(node);
|
||||
if ((functionFlags & FunctionFlags.Generator) === 0) { // Async function or normal function
|
||||
const returnOrPromisedType = returnTypeNode && (functionFlags & FunctionFlags.Async
|
||||
? checkAsyncFunctionReturnType(node) // Async function
|
||||
: getTypeFromTypeNode(returnTypeNode)); // normal function
|
||||
const returnOrPromisedType = getReturnOrPromisedType(node, functionFlags);
|
||||
checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, returnOrPromisedType);
|
||||
}
|
||||
|
||||
if (produceDiagnostics && !returnTypeNode) {
|
||||
if (produceDiagnostics && !getEffectiveReturnTypeNode(node)) {
|
||||
// Report an implicit any error if there is no body, no explicit return type, and node is not a private method
|
||||
// in an ambient context
|
||||
if (noImplicitAny && nodeIsMissing(body) && !isPrivateWithinAmbient(node)) {
|
||||
@@ -23523,6 +23533,13 @@ namespace ts {
|
||||
// yielded values. The only way to trigger these errors is to try checking its return type.
|
||||
getReturnTypeOfSignature(getSignatureFromDeclaration(node));
|
||||
}
|
||||
// A js function declaration can have a @type tag instead of a return type node, but that type must have a call signature
|
||||
if (isInJavaScriptFile(node)) {
|
||||
const typeTag = getJSDocTypeTag(node);
|
||||
if (typeTag && typeTag.typeExpression && !getSignaturesOfType(getTypeFromTypeNode(typeTag.typeExpression), SignatureKind.Call).length) {
|
||||
error(typeTag, Diagnostics.The_type_of_a_function_declaration_must_be_callable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24785,7 +24802,7 @@ namespace ts {
|
||||
error(node, Diagnostics.Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class);
|
||||
}
|
||||
}
|
||||
else if (getEffectiveReturnTypeNode(func) || isGetAccessorWithAnnotatedSetAccessor(func)) {
|
||||
else if (getEffectiveReturnTypeNode(func) || isGetAccessorWithAnnotatedSetAccessor(func) || getReturnTypeOfTypeTag(func)) {
|
||||
if (functionFlags & FunctionFlags.Async) { // Async function
|
||||
const promisedType = getPromisedTypeOfPromise(returnType);
|
||||
const awaitedType = checkAwaitedType(exprType, node, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member);
|
||||
|
||||
@@ -4021,6 +4021,10 @@
|
||||
"category": "Error",
|
||||
"code": 8029
|
||||
},
|
||||
"The type of a function declaration must be callable.": {
|
||||
"category": "Error",
|
||||
"code": 8030
|
||||
},
|
||||
"Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clause.": {
|
||||
"category": "Error",
|
||||
"code": 9002
|
||||
|
||||
Reference in New Issue
Block a user