diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 51c5001204f02..d242b1b58bed9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -25458,8 +25458,8 @@ namespace ts { if (functionFlags & FunctionFlags.Async) { // Async function or AsyncGenerator function // Get the awaited type without the `Awaited` alias - const contextualAwaitedType = mapType(contextualReturnType, getAwaitedType); - return contextualAwaitedType && getUnionType([unwrapAwaitedType(contextualAwaitedType), createPromiseLikeType(contextualAwaitedType)]); + const contextualAwaitedType = mapType(contextualReturnType, getAwaitedTypeNoAlias); + return contextualAwaitedType && getUnionType([contextualAwaitedType, createPromiseLikeType(contextualAwaitedType)]); } return contextualReturnType; // Regular function or Generator function @@ -25471,8 +25471,8 @@ namespace ts { function getContextualTypeForAwaitOperand(node: AwaitExpression, contextFlags?: ContextFlags): Type | undefined { const contextualType = getContextualType(node, contextFlags); if (contextualType) { - const contextualAwaitedType = getAwaitedType(contextualType); - return contextualAwaitedType && getUnionType([unwrapAwaitedType(contextualAwaitedType), createPromiseLikeType(contextualAwaitedType)]); + const contextualAwaitedType = getAwaitedTypeNoAlias(contextualType); + return contextualAwaitedType && getUnionType([contextualAwaitedType, createPromiseLikeType(contextualAwaitedType)]); } return undefined; } @@ -31136,7 +31136,8 @@ namespace ts { const globalPromiseType = getGlobalPromiseType(/*reportErrors*/ true); if (globalPromiseType !== emptyGenericType) { // if the promised type is itself a promise, get the underlying type; otherwise, fallback to the promised type - promisedType = getAwaitedType(promisedType) || unknownType; + // Unwrap an `Awaited` to `T` to improve inference. + promisedType = getAwaitedTypeNoAlias(unwrapAwaitedType(promisedType)) || unknownType; return createTypeReference(globalPromiseType, [promisedType]); } @@ -31148,7 +31149,8 @@ namespace ts { const globalPromiseLikeType = getGlobalPromiseLikeType(/*reportErrors*/ true); if (globalPromiseLikeType !== emptyGenericType) { // if the promised type is itself a promise, get the underlying type; otherwise, fallback to the promised type - promisedType = getAwaitedType(promisedType) || unknownType; + // Unwrap an `Awaited` to `T` to improve inference. + promisedType = getAwaitedTypeNoAlias(unwrapAwaitedType(promisedType)) || unknownType; return createTypeReference(globalPromiseLikeType, [promisedType]); } @@ -31205,7 +31207,7 @@ namespace ts { // Promise/A+ compatible implementation will always assimilate any foreign promise, so the // return type of the body should be unwrapped to its awaited type, which we will wrap in // the native Promise type later in this function. - returnType = checkAwaitedType(returnType, /*errorNode*/ func, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member); + returnType = unwrapAwaitedType(checkAwaitedType(returnType, /*withAlias*/ false, /*errorNode*/ func, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member)); } } else if (isGenerator) { // Generator or AsyncGenerator function @@ -31438,7 +31440,7 @@ namespace ts { // Promise/A+ compatible implementation will always assimilate any foreign promise, so the // return type of the body should be unwrapped to its awaited type, which should be wrapped in // the native Promise type by the caller. - type = checkAwaitedType(type, func, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member); + type = unwrapAwaitedType(checkAwaitedType(type, /*withAlias*/ false, func, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member)); } if (type.flags & TypeFlags.Never) { hasReturnOfTypeNever = true; @@ -31640,7 +31642,7 @@ namespace ts { 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); + const awaitedType = checkAwaitedType(exprType, /*withAlias*/ false, node.body, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member); checkTypeAssignableToAndOptionallyElaborate(awaitedType, returnOrPromisedType, node.body, node.body); } else { // Normal function @@ -31857,7 +31859,7 @@ namespace ts { } const operandType = checkExpression(node.expression); - const awaitedType = checkAwaitedType(operandType, node, Diagnostics.Type_of_await_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member); + const awaitedType = checkAwaitedType(operandType, /*withAlias*/ true, node, Diagnostics.Type_of_await_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member); if (awaitedType === operandType && awaitedType !== errorType && !(operandType.flags & TypeFlags.AnyOrUnknown)) { addErrorOrSuggestion(/*isError*/ false, createDiagnosticForNode(node, Diagnostics.await_has_no_effect_on_the_type_of_this_expression)); } @@ -32809,8 +32811,8 @@ namespace ts { let wouldWorkWithAwait = false; const errNode = errorNode || operatorToken; if (isRelated) { - const awaitedLeftType = unwrapAwaitedType(getAwaitedType(leftType)); - const awaitedRightType = unwrapAwaitedType(getAwaitedType(rightType)); + const awaitedLeftType = getAwaitedTypeNoAlias(leftType); + const awaitedRightType = getAwaitedTypeNoAlias(rightType); wouldWorkWithAwait = !(awaitedLeftType === leftType && awaitedRightType === rightType) && !!(awaitedLeftType && awaitedRightType) && isRelated(awaitedLeftType, awaitedRightType); @@ -34892,12 +34894,15 @@ namespace ts { /** * Gets the "awaited type" of a type. * @param type The type to await. + * @param withAlias When `true`, wraps the "awaited type" in `Awaited` if needed. * @remarks The "awaited type" of an expression is its "promised type" if the expression is a * Promise-like type; otherwise, it is the type of the expression. This is used to reflect * The runtime behavior of the `await` keyword. */ - function checkAwaitedType(type: Type, errorNode: Node, diagnosticMessage: DiagnosticMessage, arg0?: string | number): Type { - const awaitedType = getAwaitedType(type, errorNode, diagnosticMessage, arg0); + function checkAwaitedType(type: Type, withAlias: boolean, errorNode: Node, diagnosticMessage: DiagnosticMessage, arg0?: string | number): Type { + const awaitedType = withAlias ? + getAwaitedType(type, errorNode, diagnosticMessage, arg0) : + getAwaitedTypeNoAlias(type, errorNode, diagnosticMessage, arg0); return awaitedType || errorType; } @@ -34931,10 +34936,7 @@ namespace ts { /** * For a generic `Awaited`, gets `T`. */ - function unwrapAwaitedType(type: Type): Type; - function unwrapAwaitedType(type: Type | undefined): Type | undefined; - function unwrapAwaitedType(type: Type | undefined) { - if (!type) return undefined; + function unwrapAwaitedType(type: Type) { return type.flags & TypeFlags.Union ? mapType(type, unwrapAwaitedType) : isAwaitedTypeInstantiation(type) ? type.aliasTypeArguments[0] : type; @@ -34989,6 +34991,16 @@ namespace ts { * This is used to reflect the runtime behavior of the `await` keyword. */ function getAwaitedType(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage, arg0?: string | number): Type | undefined { + const awaitedType = getAwaitedTypeNoAlias(type, errorNode, diagnosticMessage, arg0); + return awaitedType && createAwaitedTypeIfNeeded(awaitedType); + } + + /** + * Gets the "awaited type" of a type without introducing an `Awaited` wrapper. + * + * @see {@link getAwaitedType} + */ + function getAwaitedTypeNoAlias(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage, arg0?: string | number): Type | undefined { if (isTypeAny(type)) { return type; } @@ -35001,14 +35013,13 @@ namespace ts { // If we've already cached an awaited type, return a possible `Awaited` for it. const typeAsAwaitable = type as PromiseOrAwaitableType; if (typeAsAwaitable.awaitedTypeOfType) { - return createAwaitedTypeIfNeeded(typeAsAwaitable.awaitedTypeOfType); + return typeAsAwaitable.awaitedTypeOfType; } // For a union, get a union of the awaited types of each constituent. if (type.flags & TypeFlags.Union) { - const mapper = errorNode ? (constituentType: Type) => getAwaitedType(constituentType, errorNode, diagnosticMessage, arg0) : getAwaitedType; - typeAsAwaitable.awaitedTypeOfType = mapType(type, mapper); - return typeAsAwaitable.awaitedTypeOfType && createAwaitedTypeIfNeeded(typeAsAwaitable.awaitedTypeOfType); + const mapper = errorNode ? (constituentType: Type) => getAwaitedTypeNoAlias(constituentType, errorNode, diagnosticMessage, arg0) : getAwaitedTypeNoAlias; + return typeAsAwaitable.awaitedTypeOfType = mapType(type, mapper); } const promisedType = getPromisedTypeOfPromise(type); @@ -35056,14 +35067,14 @@ namespace ts { // Keep track of the type we're about to unwrap to avoid bad recursive promise types. // See the comments above for more information. awaitedTypeStack.push(type.id); - const awaitedType = getAwaitedType(promisedType, errorNode, diagnosticMessage, arg0); + const awaitedType = getAwaitedTypeNoAlias(promisedType, errorNode, diagnosticMessage, arg0); awaitedTypeStack.pop(); if (!awaitedType) { return undefined; } - return createAwaitedTypeIfNeeded(typeAsAwaitable.awaitedTypeOfType = awaitedType); + return typeAsAwaitable.awaitedTypeOfType = awaitedType; } // The type was not a promise, so it could not be unwrapped any further. @@ -35089,7 +35100,7 @@ namespace ts { return undefined; } - return createAwaitedTypeIfNeeded(typeAsAwaitable.awaitedTypeOfType = type); + return typeAsAwaitable.awaitedTypeOfType = type; } /** @@ -35139,7 +35150,7 @@ namespace ts { if (globalPromiseType !== emptyGenericType && !isReferenceToType(returnType, globalPromiseType)) { // The promise type was not a valid type reference to the global promise type, so we // report an error and return the unknown type. - error(returnTypeNode, Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type_Did_you_mean_to_write_Promise_0, typeToString(unwrapAwaitedType(getAwaitedType(returnType)) || voidType)); + error(returnTypeNode, Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type_Did_you_mean_to_write_Promise_0, typeToString(getAwaitedTypeNoAlias(returnType) || voidType)); return; } } @@ -35192,7 +35203,7 @@ namespace ts { return; } } - checkAwaitedType(returnType, node, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member); + checkAwaitedType(returnType, /*withAlias*/ false, node, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member); } /** Check a decorator */ @@ -37473,7 +37484,7 @@ namespace ts { const isGenerator = !!(functionFlags & FunctionFlags.Generator); const isAsync = !!(functionFlags & FunctionFlags.Async); return isGenerator ? getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, returnType, isAsync) || errorType : - isAsync ? unwrapAwaitedType(getAwaitedType(returnType)) || errorType : + isAsync ? getAwaitedTypeNoAlias(returnType) || errorType : returnType; } @@ -37517,7 +37528,7 @@ namespace ts { else if (getReturnTypeFromAnnotation(container)) { 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) + ? checkAwaitedType(exprType, /*withAlias*/ false, node, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member) : exprType; if (unwrappedReturnType) { // If the function has a return type, but promisedType is diff --git a/tests/baselines/reference/awaitedTypeStrictNull.errors.txt b/tests/baselines/reference/awaitedTypeStrictNull.errors.txt index aa2007e54e4b7..ac8f375f4f02e 100644 --- a/tests/baselines/reference/awaitedTypeStrictNull.errors.txt +++ b/tests/baselines/reference/awaitedTypeStrictNull.errors.txt @@ -47,6 +47,22 @@ tests/cases/compiler/awaitedTypeStrictNull.ts(22,12): error TS2589: Type instant ]) } + // https://github.com/microsoft/TypeScript/issues/45924 + class Api { + // Should result in `Promise` instead of `Promise>`. + async post() { return this.request(); } + async request(): Promise { throw new Error(); } + } + + declare const api: Api; + interface Obj { x: number } + + async function fn(): Promise { + // Per #45924, this was failing due to incorrect inference both above and here. + // Should not error. + return api.post(); + } + // helps with tests where '.types' just prints out the type alias name type _Expect = TActual; \ No newline at end of file diff --git a/tests/baselines/reference/awaitedTypeStrictNull.js b/tests/baselines/reference/awaitedTypeStrictNull.js index 82c1286111532..a4d69c5ebeb32 100644 --- a/tests/baselines/reference/awaitedTypeStrictNull.js +++ b/tests/baselines/reference/awaitedTypeStrictNull.js @@ -39,6 +39,22 @@ async function main() { ]) } +// https://github.com/microsoft/TypeScript/issues/45924 +class Api { + // Should result in `Promise` instead of `Promise>`. + async post() { return this.request(); } + async request(): Promise { throw new Error(); } +} + +declare const api: Api; +interface Obj { x: number } + +async function fn(): Promise { + // Per #45924, this was failing due to incorrect inference both above and here. + // Should not error. + return api.post(); +} + // helps with tests where '.types' just prints out the type alias name type _Expect = TActual; @@ -56,3 +72,14 @@ async function main() { MaybePromise(true), ]); } +// https://github.com/microsoft/TypeScript/issues/45924 +class Api { + // Should result in `Promise` instead of `Promise>`. + async post() { return this.request(); } + async request() { throw new Error(); } +} +async function fn() { + // Per #45924, this was failing due to incorrect inference both above and here. + // Should not error. + return api.post(); +} diff --git a/tests/baselines/reference/awaitedTypeStrictNull.symbols b/tests/baselines/reference/awaitedTypeStrictNull.symbols index b928a63fe6bd5..ab59248aeaae2 100644 --- a/tests/baselines/reference/awaitedTypeStrictNull.symbols +++ b/tests/baselines/reference/awaitedTypeStrictNull.symbols @@ -60,21 +60,21 @@ type T12 = Awaited>>; type T13 = _Expect> | string | null>, /*expected*/ string | number | null>; // otherwise just prints T13 in types tests, which isn't very helpful >T13 : Symbol(T13, Decl(awaitedTypeStrictNull.ts, 11, 45)) ->_Expect : Symbol(_Expect, Decl(awaitedTypeStrictNull.ts, 38, 1)) +>_Expect : Symbol(_Expect, Decl(awaitedTypeStrictNull.ts, 54, 1)) >Awaited : Symbol(Awaited, Decl(lib.es5.d.ts, --, --)) >Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) >Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) type T14 = _Expect> | string | undefined>, /*expected*/ string | number | undefined>; // otherwise just prints T14 in types tests, which isn't very helpful >T14 : Symbol(T14, Decl(awaitedTypeStrictNull.ts, 12, 107)) ->_Expect : Symbol(_Expect, Decl(awaitedTypeStrictNull.ts, 38, 1)) +>_Expect : Symbol(_Expect, Decl(awaitedTypeStrictNull.ts, 54, 1)) >Awaited : Symbol(Awaited, Decl(lib.es5.d.ts, --, --)) >Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) >Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) type T15 = _Expect> | string | null | undefined>, /*expected*/ string | number | null | undefined>; // otherwise just prints T15 in types tests, which isn't very helpful >T15 : Symbol(T15, Decl(awaitedTypeStrictNull.ts, 13, 117)) ->_Expect : Symbol(_Expect, Decl(awaitedTypeStrictNull.ts, 38, 1)) +>_Expect : Symbol(_Expect, Decl(awaitedTypeStrictNull.ts, 54, 1)) >Awaited : Symbol(Awaited, Decl(lib.es5.d.ts, --, --)) >Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) >Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) @@ -161,11 +161,60 @@ async function main() { ]) } +// https://github.com/microsoft/TypeScript/issues/45924 +class Api { +>Api : Symbol(Api, Decl(awaitedTypeStrictNull.ts, 38, 1)) +>D : Symbol(D, Decl(awaitedTypeStrictNull.ts, 41, 10)) + + // Should result in `Promise` instead of `Promise>`. + async post() { return this.request(); } +>post : Symbol(Api.post, Decl(awaitedTypeStrictNull.ts, 41, 19)) +>T : Symbol(T, Decl(awaitedTypeStrictNull.ts, 43, 12)) +>D : Symbol(D, Decl(awaitedTypeStrictNull.ts, 41, 10)) +>this.request : Symbol(Api.request, Decl(awaitedTypeStrictNull.ts, 43, 50)) +>this : Symbol(Api, Decl(awaitedTypeStrictNull.ts, 38, 1)) +>request : Symbol(Api.request, Decl(awaitedTypeStrictNull.ts, 43, 50)) +>T : Symbol(T, Decl(awaitedTypeStrictNull.ts, 43, 12)) + + async request(): Promise { throw new Error(); } +>request : Symbol(Api.request, Decl(awaitedTypeStrictNull.ts, 43, 50)) +>D : Symbol(D, Decl(awaitedTypeStrictNull.ts, 44, 15)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) +>D : Symbol(D, Decl(awaitedTypeStrictNull.ts, 44, 15)) +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +} + +declare const api: Api; +>api : Symbol(api, Decl(awaitedTypeStrictNull.ts, 47, 13)) +>Api : Symbol(Api, Decl(awaitedTypeStrictNull.ts, 38, 1)) + +interface Obj { x: number } +>Obj : Symbol(Obj, Decl(awaitedTypeStrictNull.ts, 47, 23)) +>x : Symbol(Obj.x, Decl(awaitedTypeStrictNull.ts, 48, 15)) + +async function fn(): Promise { +>fn : Symbol(fn, Decl(awaitedTypeStrictNull.ts, 48, 27)) +>T : Symbol(T, Decl(awaitedTypeStrictNull.ts, 50, 18)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) +>T : Symbol(T, Decl(awaitedTypeStrictNull.ts, 50, 18)) +>K : Symbol(K, Decl(awaitedTypeStrictNull.ts, 50, 54)) +>T : Symbol(T, Decl(awaitedTypeStrictNull.ts, 50, 18)) +>Obj : Symbol(Obj, Decl(awaitedTypeStrictNull.ts, 47, 23)) +>Obj : Symbol(Obj, Decl(awaitedTypeStrictNull.ts, 47, 23)) + + // Per #45924, this was failing due to incorrect inference both above and here. + // Should not error. + return api.post(); +>api.post : Symbol(Api.post, Decl(awaitedTypeStrictNull.ts, 41, 19)) +>api : Symbol(api, Decl(awaitedTypeStrictNull.ts, 47, 13)) +>post : Symbol(Api.post, Decl(awaitedTypeStrictNull.ts, 41, 19)) +} + // helps with tests where '.types' just prints out the type alias name type _Expect = TActual; ->_Expect : Symbol(_Expect, Decl(awaitedTypeStrictNull.ts, 38, 1)) ->TActual : Symbol(TActual, Decl(awaitedTypeStrictNull.ts, 41, 13)) ->TExpected : Symbol(TExpected, Decl(awaitedTypeStrictNull.ts, 41, 39)) ->TExpected : Symbol(TExpected, Decl(awaitedTypeStrictNull.ts, 41, 39)) ->TActual : Symbol(TActual, Decl(awaitedTypeStrictNull.ts, 41, 13)) +>_Expect : Symbol(_Expect, Decl(awaitedTypeStrictNull.ts, 54, 1)) +>TActual : Symbol(TActual, Decl(awaitedTypeStrictNull.ts, 57, 13)) +>TExpected : Symbol(TExpected, Decl(awaitedTypeStrictNull.ts, 57, 39)) +>TExpected : Symbol(TExpected, Decl(awaitedTypeStrictNull.ts, 57, 39)) +>TActual : Symbol(TActual, Decl(awaitedTypeStrictNull.ts, 57, 13)) diff --git a/tests/baselines/reference/awaitedTypeStrictNull.types b/tests/baselines/reference/awaitedTypeStrictNull.types index 18312dda7c8e4..f5824eb476eab 100644 --- a/tests/baselines/reference/awaitedTypeStrictNull.types +++ b/tests/baselines/reference/awaitedTypeStrictNull.types @@ -128,6 +128,42 @@ async function main() { ]) } +// https://github.com/microsoft/TypeScript/issues/45924 +class Api { +>Api : Api + + // Should result in `Promise` instead of `Promise>`. + async post() { return this.request(); } +>post : () => Promise +>this.request() : Promise +>this.request : () => Promise +>this : this +>request : () => Promise + + async request(): Promise { throw new Error(); } +>request : () => Promise +>new Error() : Error +>Error : ErrorConstructor +} + +declare const api: Api; +>api : Api<{}> + +interface Obj { x: number } +>x : number + +async function fn(): Promise { +>fn : () => Promise + + // Per #45924, this was failing due to incorrect inference both above and here. + // Should not error. + return api.post(); +>api.post() : Promise +>api.post : () => Promise +>api : Api<{}> +>post : () => Promise +} + // helps with tests where '.types' just prints out the type alias name type _Expect = TActual; >_Expect : TActual diff --git a/tests/cases/compiler/awaitedTypeStrictNull.ts b/tests/cases/compiler/awaitedTypeStrictNull.ts index e5726653a5eb5..b3672a48e65cb 100644 --- a/tests/cases/compiler/awaitedTypeStrictNull.ts +++ b/tests/cases/compiler/awaitedTypeStrictNull.ts @@ -41,5 +41,21 @@ async function main() { ]) } +// https://github.com/microsoft/TypeScript/issues/45924 +class Api { + // Should result in `Promise` instead of `Promise>`. + async post() { return this.request(); } + async request(): Promise { throw new Error(); } +} + +declare const api: Api; +interface Obj { x: number } + +async function fn(): Promise { + // Per #45924, this was failing due to incorrect inference both above and here. + // Should not error. + return api.post(); +} + // helps with tests where '.types' just prints out the type alias name type _Expect = TActual;