Skip to content

Commit 66ad2e8

Browse files
committed
Added error when return type is not the global Promise
1 parent 40bac6d commit 66ad2e8

File tree

2 files changed

+41
-20
lines changed

2 files changed

+41
-20
lines changed

src/compiler/checker.ts

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2629,7 +2629,7 @@ namespace ts {
26292629
}
26302630
}
26312631
else if (declaration.kind === SyntaxKind.Parameter) {
2632-
// If it's a parameter, see if the parent has a jsdoc comment with an @param
2632+
// If it's a parameter, see if the parent has a jsdoc comment with an @param
26332633
// annotation.
26342634
const paramTag = getCorrespondingJSDocParameterTag(<ParameterDeclaration>declaration);
26352635
if (paramTag && paramTag.typeExpression) {
@@ -2644,7 +2644,7 @@ namespace ts {
26442644
function getTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration): Type {
26452645
if (declaration.parserContextFlags & ParserContextFlags.JavaScriptFile) {
26462646
// If this is a variable in a JavaScript file, then use the JSDoc type (if it has
2647-
// one as its type), otherwise fallback to the below standard TS codepaths to
2647+
// one as its type), otherwise fallback to the below standard TS codepaths to
26482648
// try to figure it out.
26492649
const type = getTypeForVariableLikeDeclarationFromJSDocComment(declaration);
26502650
if (type && type !== unknownType) {
@@ -4069,7 +4069,7 @@ namespace ts {
40694069
const isJSConstructSignature = isJSDocConstructSignature(declaration);
40704070
let returnType: Type = undefined;
40714071

4072-
// If this is a JSDoc construct signature, then skip the first parameter in the
4072+
// If this is a JSDoc construct signature, then skip the first parameter in the
40734073
// parameter list. The first parameter represents the return type of the construct
40744074
// signature.
40754075
for (let i = isJSConstructSignature ? 1 : 0, n = declaration.parameters.length; i < n; i++) {
@@ -4472,7 +4472,7 @@ namespace ts {
44724472
}
44734473

44744474
if (symbol.flags & SymbolFlags.Value && node.kind === SyntaxKind.JSDocTypeReference) {
4475-
// A JSDocTypeReference may have resolved to a value (as opposed to a type). In
4475+
// A JSDocTypeReference may have resolved to a value (as opposed to a type). In
44764476
// that case, the type of this reference is just the type of the value we resolved
44774477
// to.
44784478
return getTypeOfSymbol(symbol);
@@ -10479,7 +10479,7 @@ namespace ts {
1047910479

1048010480
/*
1048110481
*TypeScript Specification 1.0 (6.3) - July 2014
10482-
* An explicitly typed function whose return type isn't the Void type,
10482+
* An explicitly typed function whose return type isn't the Void type,
1048310483
* the Any type, or a union type containing the Void or Any type as a constituent
1048410484
* must have at least one return statement somewhere in its body.
1048510485
* An exception to this rule is if the function implementation consists of a single 'throw' statement.
@@ -12508,6 +12508,33 @@ namespace ts {
1250812508
}
1250912509
}
1251012510

12511+
/**
12512+
* Checks that the return type provided is an instantiation of the global Promise<T> type
12513+
* and returns the awaited type of the return type.
12514+
*/
12515+
function checkCorrectPromiseType(returnType: Type, location: Node) {
12516+
if (returnType === unknownType) {
12517+
// The return type already had some other error, so we ignore and return
12518+
// the unknown type.
12519+
return unknownType;
12520+
}
12521+
12522+
const globalPromiseType = getGlobalPromiseType();
12523+
if (globalPromiseType === emptyGenericType
12524+
|| globalPromiseType === getTargetType(returnType)) {
12525+
// Either we couldn't resolve the global promise type, which would have already
12526+
// reported an error, or we could resolve it and the return type is a valid type
12527+
// reference to the global type. In either case, we return the awaited type for
12528+
// the return type.
12529+
return checkAwaitedType(returnType, location, Diagnostics.An_async_function_or_method_must_have_a_valid_awaitable_return_type);
12530+
}
12531+
12532+
// The promise type was not a valid type reference to the global promise type, so we
12533+
// report an error and return the unknown type.
12534+
error(location, Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T);
12535+
return unknownType;
12536+
}
12537+
1251112538
/**
1251212539
* Checks the return type of an async function to ensure it is a compatible
1251312540
* Promise implementation.
@@ -12522,6 +12549,11 @@ namespace ts {
1252212549
* callable `then` signature.
1252312550
*/
1252412551
function checkAsyncFunctionReturnType(node: FunctionLikeDeclaration): Type {
12552+
if (languageVersion >= ScriptTarget.ES6) {
12553+
const returnType = getTypeFromTypeNode(node.type);
12554+
return checkCorrectPromiseType(returnType, node.type);
12555+
}
12556+
1252512557
const globalPromiseConstructorLikeType = getGlobalPromiseConstructorLikeType();
1252612558
if (globalPromiseConstructorLikeType === emptyObjectType) {
1252712559
// If we couldn't resolve the global PromiseConstructorLike type we cannot verify
@@ -12563,21 +12595,6 @@ namespace ts {
1256312595
return unknownType;
1256412596
}
1256512597

12566-
if (languageVersion >= ScriptTarget.ES6) {
12567-
const promisedType = getPromisedType(promiseType);
12568-
if (!promisedType) {
12569-
error(node, Diagnostics.Type_0_is_not_a_valid_async_function_return_type, typeToString(promiseType));
12570-
return unknownType;
12571-
}
12572-
12573-
const promiseInstantiation = createPromiseType(promisedType);
12574-
if (!checkTypeAssignableTo(promiseInstantiation, promiseType, node.type, Diagnostics.Type_0_is_not_a_valid_async_function_return_type)) {
12575-
return unknownType;
12576-
}
12577-
12578-
return promisedType;
12579-
}
12580-
1258112598
const promiseConstructor = getNodeLinks(node.type).resolvedSymbol;
1258212599
if (!promiseConstructor || !symbolIsValue(promiseConstructor)) {
1258312600
const typeName = promiseConstructor

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@
195195
"category": "Error",
196196
"code": 1063
197197
},
198+
"The return type of an async function or method must be the global Promise<T>.": {
199+
"category": "Error",
200+
"code": 1064
201+
},
198202
"In ambient enum declarations member initializer must be constant expression.": {
199203
"category": "Error",
200204
"code": 1066

0 commit comments

Comments
 (0)