Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 5 additions & 13 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27243,7 +27243,7 @@ namespace ts {
}

const functionFlags = getFunctionFlags(func);
const type = returnType && getReturnOrPromisedType(returnType, functionFlags);
const type = returnType && unwrapReturnType(returnType, functionFlags);

// Functions with with an explicitly specified 'void' or 'any' return type don't need any return expressions.
if (type && maybeTypeOfKind(type, TypeFlags.Any | TypeFlags.Void)) {
Expand Down Expand Up @@ -27363,14 +27363,6 @@ namespace ts {
}
}

function getReturnOrPromisedType(type: Type | undefined, functionFlags: FunctionFlags) {
const isGenerator = !!(functionFlags & FunctionFlags.Generator);
const isAsync = !!(functionFlags & FunctionFlags.Async);
return type && isGenerator ? getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, type, isAsync) || errorType :
type && isAsync ? getAwaitedType(type) || errorType :
type;
}

function checkFunctionExpressionOrObjectLiteralMethodDeferred(node: ArrowFunction | FunctionExpression | MethodDeclaration) {
Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node));

Expand Down Expand Up @@ -27398,7 +27390,7 @@ namespace ts {
// check assignability of the awaited type of the expression body against the promised type of
// its return type annotation.
const exprType = checkExpression(node.body);
const returnOrPromisedType = getReturnOrPromisedType(returnType, functionFlags);
const returnOrPromisedType = returnType && unwrapReturnType(returnType, functionFlags);
if (returnOrPromisedType) {
if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async) { // Async function
const awaitedType = checkAwaitedType(exprType, node.body, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member);
Expand Down Expand Up @@ -32686,8 +32678,8 @@ namespace ts {
function unwrapReturnType(returnType: Type, functionFlags: FunctionFlags) {
const isGenerator = !!(functionFlags & FunctionFlags.Generator);
const isAsync = !!(functionFlags & FunctionFlags.Async);
return isGenerator ? getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, returnType, isAsync) || errorType :
isAsync ? getPromisedTypeOfPromise(returnType) || errorType :
return isGenerator ? getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, returnType, isAsync) ?? errorType :
isAsync ? getAwaitedType(returnType) ?? errorType :
returnType;
}

Expand Down Expand Up @@ -32724,7 +32716,7 @@ namespace ts {
}
}
else if (getReturnTypeFromAnnotation(func)) {
const unwrappedReturnType = unwrapReturnType(returnType, functionFlags);
const unwrappedReturnType = unwrapReturnType(returnType, functionFlags) ?? returnType;
const unwrappedExprType = functionFlags & FunctionFlags.Async
? 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)
: exprType;
Expand Down
38 changes: 38 additions & 0 deletions tests/baselines/reference/asyncArrowFunction_allowJs.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
tests/cases/conformance/async/es2017/asyncArrowFunction/file.js(3,17): error TS2322: Type '0' is not assignable to type 'string'.
tests/cases/conformance/async/es2017/asyncArrowFunction/file.js(7,23): error TS2322: Type '0' is not assignable to type 'string'.
tests/cases/conformance/async/es2017/asyncArrowFunction/file.js(12,2): error TS2322: Type '0' is not assignable to type 'string'.
tests/cases/conformance/async/es2017/asyncArrowFunction/file.js(19,3): error TS2345: Argument of type '() => Promise<number>' is not assignable to parameter of type '() => string'.
Type 'Promise<number>' is not assignable to type 'string'.


==== tests/cases/conformance/async/es2017/asyncArrowFunction/file.js (4 errors) ====
// Error (good)
/** @type {function(): string} */
const a = () => 0
~
!!! error TS2322: Type '0' is not assignable to type 'string'.

// Error (good)
/** @type {function(): string} */
const b = async () => 0
~
!!! error TS2322: Type '0' is not assignable to type 'string'.

// No error (bad)
/** @type {function(): string} */
const c = async () => {
return 0
~~~~~~~~
!!! error TS2322: Type '0' is not assignable to type 'string'.
}

/** @type {function(function(): string): void} */
const f = (p) => {}

// Error (good)
f(async () => {
~~~~~~~~~~~~~
!!! error TS2345: Argument of type '() => Promise<number>' is not assignable to parameter of type '() => string'.
!!! error TS2345: Type 'Promise<number>' is not assignable to type 'string'.
return 0
})
30 changes: 30 additions & 0 deletions tests/baselines/reference/asyncArrowFunction_allowJs.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
=== tests/cases/conformance/async/es2017/asyncArrowFunction/file.js ===
// Error (good)
/** @type {function(): string} */
const a = () => 0
>a : Symbol(a, Decl(file.js, 2, 5))

// Error (good)
/** @type {function(): string} */
const b = async () => 0
>b : Symbol(b, Decl(file.js, 6, 5))

// No error (bad)
/** @type {function(): string} */
const c = async () => {
>c : Symbol(c, Decl(file.js, 10, 5))

return 0
}

/** @type {function(function(): string): void} */
const f = (p) => {}
>f : Symbol(f, Decl(file.js, 15, 5))
>p : Symbol(p, Decl(file.js, 15, 11))

// Error (good)
f(async () => {
>f : Symbol(f, Decl(file.js, 15, 5))

return 0
})
41 changes: 41 additions & 0 deletions tests/baselines/reference/asyncArrowFunction_allowJs.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
=== tests/cases/conformance/async/es2017/asyncArrowFunction/file.js ===
// Error (good)
/** @type {function(): string} */
const a = () => 0
>a : () => string
>() => 0 : () => string
>0 : 0

// Error (good)
/** @type {function(): string} */
const b = async () => 0
>b : () => string
>async () => 0 : () => string
>0 : 0

// No error (bad)
/** @type {function(): string} */
const c = async () => {
>c : () => string
>async () => { return 0} : () => string

return 0
>0 : 0
}

/** @type {function(function(): string): void} */
const f = (p) => {}
>f : (arg0: () => string) => void
>(p) => {} : (p: () => string) => void
>p : () => string

// Error (good)
f(async () => {
>f(async () => { return 0}) : void
>f : (arg0: () => string) => void
>async () => { return 0} : () => Promise<number>

return 0
>0 : 0

})
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// @allowJs: true
// @checkJs: true
// @noEmit: true
// @target: es2017
// @filename: file.js

// Error (good)
/** @type {function(): string} */
const a = () => 0

// Error (good)
/** @type {function(): string} */
const b = async () => 0

// No error (bad)
/** @type {function(): string} */
const c = async () => {
return 0
}

/** @type {function(function(): string): void} */
const f = (p) => {}

// Error (good)
f(async () => {
return 0
})