mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-14 02:15:12 -06:00
Merge pull request #7450 from Microsoft/noImplicitReturnsInAsync
unwrap promised typed in async function before doing 'noImplicitRetur…
This commit is contained in:
commit
5d5fee2ef1
@ -10860,11 +10860,11 @@ namespace ts {
|
||||
// If return type annotation is omitted check if function has any explicit return statements.
|
||||
// If it does not have any - its inferred return type is void - don't do any checks.
|
||||
// Otherwise get inferred return type from function body and report error only if it is not void / anytype
|
||||
const inferredReturnType = hasExplicitReturn
|
||||
? getReturnTypeOfSignature(getSignatureFromDeclaration(func))
|
||||
: voidType;
|
||||
|
||||
if (inferredReturnType === voidType || isTypeAny(inferredReturnType)) {
|
||||
if (!hasExplicitReturn) {
|
||||
return;
|
||||
}
|
||||
const inferredReturnType = getReturnTypeOfSignature(getSignatureFromDeclaration(func));
|
||||
if (isUnwrappedReturnTypeVoidOrAny(func, inferredReturnType)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -12743,7 +12743,7 @@ namespace ts {
|
||||
return checkNonThenableType(type, location, message);
|
||||
}
|
||||
else {
|
||||
if (type.id === promisedType.id || awaitedTypeStack.indexOf(promisedType.id) >= 0) {
|
||||
if (type.id === promisedType.id || indexOf(awaitedTypeStack, promisedType.id) >= 0) {
|
||||
// We have a bad actor in the form of a promise whose promised type is
|
||||
// the same promise type, or a mutually recursive promise. Return the
|
||||
// unknown type as we cannot guess the shape. If this were the actual
|
||||
@ -13896,6 +13896,11 @@ namespace ts {
|
||||
return !!(node.kind === SyntaxKind.GetAccessor && getSetAccessorTypeAnnotationNode(<AccessorDeclaration>getDeclarationOfKind(node.symbol, SyntaxKind.SetAccessor)));
|
||||
}
|
||||
|
||||
function isUnwrappedReturnTypeVoidOrAny(func: FunctionLikeDeclaration, returnType: Type): boolean {
|
||||
const unwrappedReturnType = isAsyncFunctionLike(func) ? getPromisedType(returnType) : returnType;
|
||||
return maybeTypeOfKind(unwrappedReturnType, TypeFlags.Void | TypeFlags.Any);
|
||||
}
|
||||
|
||||
function checkReturnStatement(node: ReturnStatement) {
|
||||
// Grammar checking
|
||||
if (!checkGrammarStatementInAmbientContext(node)) {
|
||||
@ -13944,7 +13949,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (compilerOptions.noImplicitReturns && !maybeTypeOfKind(returnType, TypeFlags.Void | TypeFlags.Any)) {
|
||||
else if (compilerOptions.noImplicitReturns && !isUnwrappedReturnTypeVoidOrAny(func, returnType)) {
|
||||
// The function has a return type, but the return statement doesn't have an expression.
|
||||
error(node, Diagnostics.Not_all_code_paths_return_a_value);
|
||||
}
|
||||
|
||||
26
tests/baselines/reference/noImplicitReturnsInAsync1.js
Normal file
26
tests/baselines/reference/noImplicitReturnsInAsync1.js
Normal file
@ -0,0 +1,26 @@
|
||||
//// [noImplicitReturnsInAsync1.ts]
|
||||
|
||||
async function test(isError: boolean = false) {
|
||||
if (isError === true) {
|
||||
return;
|
||||
}
|
||||
let x = await Promise.resolve("The test is passed without an error.");
|
||||
}
|
||||
|
||||
//// [noImplicitReturnsInAsync1.js]
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments)).next());
|
||||
});
|
||||
};
|
||||
function test(isError = false) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (isError === true) {
|
||||
return;
|
||||
}
|
||||
let x = yield Promise.resolve("The test is passed without an error.");
|
||||
});
|
||||
}
|
||||
17
tests/baselines/reference/noImplicitReturnsInAsync1.symbols
Normal file
17
tests/baselines/reference/noImplicitReturnsInAsync1.symbols
Normal file
@ -0,0 +1,17 @@
|
||||
=== tests/cases/compiler/noImplicitReturnsInAsync1.ts ===
|
||||
|
||||
async function test(isError: boolean = false) {
|
||||
>test : Symbol(test, Decl(noImplicitReturnsInAsync1.ts, 0, 0))
|
||||
>isError : Symbol(isError, Decl(noImplicitReturnsInAsync1.ts, 1, 20))
|
||||
|
||||
if (isError === true) {
|
||||
>isError : Symbol(isError, Decl(noImplicitReturnsInAsync1.ts, 1, 20))
|
||||
|
||||
return;
|
||||
}
|
||||
let x = await Promise.resolve("The test is passed without an error.");
|
||||
>x : Symbol(x, Decl(noImplicitReturnsInAsync1.ts, 5, 7))
|
||||
>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>Promise : Symbol(Promise, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
}
|
||||
23
tests/baselines/reference/noImplicitReturnsInAsync1.types
Normal file
23
tests/baselines/reference/noImplicitReturnsInAsync1.types
Normal file
@ -0,0 +1,23 @@
|
||||
=== tests/cases/compiler/noImplicitReturnsInAsync1.ts ===
|
||||
|
||||
async function test(isError: boolean = false) {
|
||||
>test : (isError?: boolean) => Promise<void>
|
||||
>isError : boolean
|
||||
>false : boolean
|
||||
|
||||
if (isError === true) {
|
||||
>isError === true : boolean
|
||||
>isError : boolean
|
||||
>true : boolean
|
||||
|
||||
return;
|
||||
}
|
||||
let x = await Promise.resolve("The test is passed without an error.");
|
||||
>x : string
|
||||
>await Promise.resolve("The test is passed without an error.") : string
|
||||
>Promise.resolve("The test is passed without an error.") : Promise<string>
|
||||
>Promise.resolve : { <T>(value: T | PromiseLike<T>): Promise<T>; (): Promise<void>; }
|
||||
>Promise : PromiseConstructor
|
||||
>resolve : { <T>(value: T | PromiseLike<T>): Promise<T>; (): Promise<void>; }
|
||||
>"The test is passed without an error." : string
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
tests/cases/compiler/noImplicitReturnsInAsync2.ts(3,16): error TS7030: Not all code paths return a value.
|
||||
tests/cases/compiler/noImplicitReturnsInAsync2.ts(25,48): error TS7030: Not all code paths return a value.
|
||||
|
||||
|
||||
==== tests/cases/compiler/noImplicitReturnsInAsync2.ts (2 errors) ====
|
||||
|
||||
// Should be an error, Promise<number>, currently retorted correctly
|
||||
async function test3(isError: boolean = true) {
|
||||
~~~~~
|
||||
!!! error TS7030: Not all code paths return a value.
|
||||
if (isError === true) {
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
|
||||
// Should not be an error, Promise<any>, currently **not** working
|
||||
async function test4(isError: boolean = true) {
|
||||
if (isError === true) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// should not be error, Promise<any> currently working correctly
|
||||
async function test5(isError: boolean = true): Promise<any> { //should not be error
|
||||
if (isError === true) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// should be error, currently reported correctly
|
||||
async function test6(isError: boolean = true): Promise<number> {
|
||||
~~~~~~~~~~~~~~~
|
||||
!!! error TS7030: Not all code paths return a value.
|
||||
if (isError === true) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// infered to be Promise<void>, should not be an error, currently reported correctly
|
||||
async function test7(isError: boolean = true) {
|
||||
if (isError === true) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
87
tests/baselines/reference/noImplicitReturnsInAsync2.js
Normal file
87
tests/baselines/reference/noImplicitReturnsInAsync2.js
Normal file
@ -0,0 +1,87 @@
|
||||
//// [noImplicitReturnsInAsync2.ts]
|
||||
|
||||
// Should be an error, Promise<number>, currently retorted correctly
|
||||
async function test3(isError: boolean = true) {
|
||||
if (isError === true) {
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
|
||||
// Should not be an error, Promise<any>, currently **not** working
|
||||
async function test4(isError: boolean = true) {
|
||||
if (isError === true) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// should not be error, Promise<any> currently working correctly
|
||||
async function test5(isError: boolean = true): Promise<any> { //should not be error
|
||||
if (isError === true) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// should be error, currently reported correctly
|
||||
async function test6(isError: boolean = true): Promise<number> {
|
||||
if (isError === true) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// infered to be Promise<void>, should not be an error, currently reported correctly
|
||||
async function test7(isError: boolean = true) {
|
||||
if (isError === true) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//// [noImplicitReturnsInAsync2.js]
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments)).next());
|
||||
});
|
||||
};
|
||||
// Should be an error, Promise<number>, currently retorted correctly
|
||||
function test3(isError = true) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (isError === true) {
|
||||
return 6;
|
||||
}
|
||||
});
|
||||
}
|
||||
// Should not be an error, Promise<any>, currently **not** working
|
||||
function test4(isError = true) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (isError === true) {
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
}
|
||||
// should not be error, Promise<any> currently working correctly
|
||||
function test5(isError = true) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (isError === true) {
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
}
|
||||
// should be error, currently reported correctly
|
||||
function test6(isError = true) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (isError === true) {
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
}
|
||||
// infered to be Promise<void>, should not be an error, currently reported correctly
|
||||
function test7(isError = true) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (isError === true) {
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
9
tests/cases/compiler/noImplicitReturnsInAsync1.ts
Normal file
9
tests/cases/compiler/noImplicitReturnsInAsync1.ts
Normal file
@ -0,0 +1,9 @@
|
||||
// @target: es6
|
||||
// @noImplicitReturns: true
|
||||
|
||||
async function test(isError: boolean = false) {
|
||||
if (isError === true) {
|
||||
return;
|
||||
}
|
||||
let x = await Promise.resolve("The test is passed without an error.");
|
||||
}
|
||||
38
tests/cases/compiler/noImplicitReturnsInAsync2.ts
Normal file
38
tests/cases/compiler/noImplicitReturnsInAsync2.ts
Normal file
@ -0,0 +1,38 @@
|
||||
// @target: es6
|
||||
// @noImplicitReturns: true
|
||||
|
||||
// Should be an error, Promise<number>, currently retorted correctly
|
||||
async function test3(isError: boolean = true) {
|
||||
if (isError === true) {
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
|
||||
// Should not be an error, Promise<any>, currently **not** working
|
||||
async function test4(isError: boolean = true) {
|
||||
if (isError === true) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// should not be error, Promise<any> currently working correctly
|
||||
async function test5(isError: boolean = true): Promise<any> { //should not be error
|
||||
if (isError === true) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// should be error, currently reported correctly
|
||||
async function test6(isError: boolean = true): Promise<number> {
|
||||
if (isError === true) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// infered to be Promise<void>, should not be an error, currently reported correctly
|
||||
async function test7(isError: boolean = true) {
|
||||
if (isError === true) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user