@@ -7566,12 +7566,21 @@ namespace ts {
75667566 const setter = getDeclarationOfKind<AccessorDeclaration>(getSymbolOfNode(declaration), SyntaxKind.SetAccessor);
75677567 return getAnnotatedAccessorType(setter);
75687568 }
7569-
7569+ const typeFromTag = getReturnTypeOfTypeTag(declaration);
7570+ if (typeFromTag) {
7571+ return typeFromTag;
7572+ }
75707573 if (nodeIsMissing((<FunctionLikeDeclaration>declaration).body)) {
75717574 return anyType;
75727575 }
75737576 }
75747577
7578+ function getReturnTypeOfTypeTag(node: SignatureDeclaration | JSDocSignature) {
7579+ const typeTag = isInJavaScriptFile(node) ? getJSDocTypeTag(node) : undefined;
7580+ const signatures = typeTag && typeTag.typeExpression && getSignaturesOfType(getTypeFromTypeNode(typeTag.typeExpression), SignatureKind.Call);
7581+ return signatures && signatures.length === 1 ? getReturnTypeOfSignature(signatures[0]) : undefined;
7582+ }
7583+
75757584 function containsArgumentsReference(declaration: SignatureDeclaration): boolean {
75767585 const links = getNodeLinks(declaration);
75777586 if (links.containsArgumentsReference === undefined) {
@@ -20539,23 +20548,28 @@ namespace ts {
2053920548 return type;
2054020549 }
2054120550
20551+ function getReturnOrPromisedType(node: FunctionLikeDeclaration | MethodSignature, functionFlags: FunctionFlags) {
20552+ const returnTypeNode = getEffectiveReturnTypeNode(node);
20553+ return returnTypeNode &&
20554+ ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async ?
20555+ checkAsyncFunctionReturnType(node, returnTypeNode) : // Async function
20556+ getTypeFromTypeNode(returnTypeNode)) || // AsyncGenerator function, Generator function, or normal function
20557+ getReturnTypeOfTypeTag(node); // type from JSDoc @type tag
20558+ }
20559+
2054220560 function checkFunctionExpressionOrObjectLiteralMethodDeferred(node: ArrowFunction | FunctionExpression | MethodDeclaration) {
2054320561 Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node));
2054420562
2054520563 const functionFlags = getFunctionFlags(node);
20546- const returnTypeNode = getEffectiveReturnTypeNode(node);
20547- const returnOrPromisedType = returnTypeNode &&
20548- ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async ?
20549- checkAsyncFunctionReturnType(node) : // Async function
20550- getTypeFromTypeNode(returnTypeNode)); // AsyncGenerator function, Generator function, or normal function
20564+ const returnOrPromisedType = getReturnOrPromisedType(node, functionFlags);
2055120565
2055220566 if ((functionFlags & FunctionFlags.Generator) === 0) { // Async function or normal function
2055320567 // return is not necessary in the body of generators
2055420568 checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, returnOrPromisedType);
2055520569 }
2055620570
2055720571 if (node.body) {
20558- if (!returnTypeNode ) {
20572+ if (!getEffectiveReturnTypeNode(node) ) {
2055920573 // There are some checks that are only performed in getReturnTypeFromBody, that may produce errors
2056020574 // we need. An example is the noImplicitAny errors resulting from widening the return expression
2056120575 // of a function. Because checking of function expression bodies is deferred, there was never an
@@ -22007,7 +22021,7 @@ namespace ts {
2200722021 }
2200822022 }
2200922023 else if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async) {
22010- checkAsyncFunctionReturnType(<FunctionLikeDeclaration>node);
22024+ checkAsyncFunctionReturnType(<FunctionLikeDeclaration>node, returnTypeNode );
2201122025 }
2201222026 }
2201322027 if (node.kind !== SyntaxKind.IndexSignature && node.kind !== SyntaxKind.JSDocFunctionType) {
@@ -23067,7 +23081,7 @@ namespace ts {
2306723081 *
2306823082 * @param node The signature to check
2306923083 */
23070- function checkAsyncFunctionReturnType(node: FunctionLikeDeclaration | MethodSignature): Type {
23084+ function checkAsyncFunctionReturnType(node: FunctionLikeDeclaration | MethodSignature, returnTypeNode: TypeNode ): Type {
2307123085 // As part of our emit for an async function, we will need to emit the entity name of
2307223086 // the return type annotation as an expression. To meet the necessary runtime semantics
2307323087 // for __awaiter, we must also check that the type of the declaration (e.g. the static
@@ -23092,7 +23106,6 @@ namespace ts {
2309223106 // then<U>(...): Promise<U>;
2309323107 // }
2309423108 //
23095- const returnTypeNode = getEffectiveReturnTypeNode(node)!; // TODO: GH#18217
2309623109 const returnType = getTypeFromTypeNode(returnTypeNode);
2309723110
2309823111 if (languageVersion >= ScriptTarget.ES2015) {
@@ -23502,15 +23515,12 @@ namespace ts {
2350223515 const body = node.kind === SyntaxKind.MethodSignature ? undefined : node.body;
2350323516 checkSourceElement(body);
2350423517
23505- const returnTypeNode = getEffectiveReturnTypeNode(node);
2350623518 if ((functionFlags & FunctionFlags.Generator) === 0) { // Async function or normal function
23507- const returnOrPromisedType = returnTypeNode && (functionFlags & FunctionFlags.Async
23508- ? checkAsyncFunctionReturnType(node) // Async function
23509- : getTypeFromTypeNode(returnTypeNode)); // normal function
23519+ const returnOrPromisedType = getReturnOrPromisedType(node, functionFlags);
2351023520 checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, returnOrPromisedType);
2351123521 }
2351223522
23513- if (produceDiagnostics && !returnTypeNode ) {
23523+ if (produceDiagnostics && !getEffectiveReturnTypeNode(node) ) {
2351423524 // Report an implicit any error if there is no body, no explicit return type, and node is not a private method
2351523525 // in an ambient context
2351623526 if (noImplicitAny && nodeIsMissing(body) && !isPrivateWithinAmbient(node)) {
@@ -23523,6 +23533,13 @@ namespace ts {
2352323533 // yielded values. The only way to trigger these errors is to try checking its return type.
2352423534 getReturnTypeOfSignature(getSignatureFromDeclaration(node));
2352523535 }
23536+ // A js function declaration can have a @type tag instead of a return type node, but that type must have a call signature
23537+ if (isInJavaScriptFile(node)) {
23538+ const typeTag = getJSDocTypeTag(node);
23539+ if (typeTag && typeTag.typeExpression && !getSignaturesOfType(getTypeFromTypeNode(typeTag.typeExpression), SignatureKind.Call).length) {
23540+ error(typeTag, Diagnostics.The_type_of_a_function_declaration_must_be_callable);
23541+ }
23542+ }
2352623543 }
2352723544 }
2352823545
@@ -24785,7 +24802,7 @@ namespace ts {
2478524802 error(node, Diagnostics.Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class);
2478624803 }
2478724804 }
24788- else if (getEffectiveReturnTypeNode(func) || isGetAccessorWithAnnotatedSetAccessor(func)) {
24805+ else if (getEffectiveReturnTypeNode(func) || isGetAccessorWithAnnotatedSetAccessor(func) || getReturnTypeOfTypeTag(func) ) {
2478924806 if (functionFlags & FunctionFlags.Async) { // Async function
2479024807 const promisedType = getPromisedTypeOfPromise(returnType);
2479124808 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);
0 commit comments