mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-12 19:31:16 -05:00
Avoid Promise<Awaited<T>> in return type inference (#45925)
This commit is contained in:
@@ -25471,8 +25471,8 @@ namespace ts {
|
||||
|
||||
if (functionFlags & FunctionFlags.Async) { // Async function or AsyncGenerator function
|
||||
// Get the awaited type without the `Awaited<T>` 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
|
||||
@@ -25484,8 +25484,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;
|
||||
}
|
||||
@@ -31158,7 +31158,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<T>` to `T` to improve inference.
|
||||
promisedType = getAwaitedTypeNoAlias(unwrapAwaitedType(promisedType)) || unknownType;
|
||||
return createTypeReference(globalPromiseType, [promisedType]);
|
||||
}
|
||||
|
||||
@@ -31170,7 +31171,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<T>` to `T` to improve inference.
|
||||
promisedType = getAwaitedTypeNoAlias(unwrapAwaitedType(promisedType)) || unknownType;
|
||||
return createTypeReference(globalPromiseLikeType, [promisedType]);
|
||||
}
|
||||
|
||||
@@ -31227,7 +31229,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<T> 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
|
||||
@@ -31460,7 +31462,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<T> 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;
|
||||
@@ -31662,7 +31664,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
|
||||
@@ -31879,7 +31881,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));
|
||||
}
|
||||
@@ -32831,8 +32833,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);
|
||||
@@ -34914,12 +34916,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<T>` 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;
|
||||
}
|
||||
|
||||
@@ -34953,10 +34958,7 @@ namespace ts {
|
||||
/**
|
||||
* For a generic `Awaited<T>`, 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;
|
||||
@@ -35011,6 +35013,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<T>` wrapper.
|
||||
*
|
||||
* @see {@link getAwaitedType}
|
||||
*/
|
||||
function getAwaitedTypeNoAlias(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage, arg0?: string | number): Type | undefined {
|
||||
if (isTypeAny(type)) {
|
||||
return type;
|
||||
}
|
||||
@@ -35023,14 +35035,13 @@ namespace ts {
|
||||
// If we've already cached an awaited type, return a possible `Awaited<T>` 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);
|
||||
@@ -35078,14 +35089,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.
|
||||
@@ -35111,7 +35122,7 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return createAwaitedTypeIfNeeded(typeAsAwaitable.awaitedTypeOfType = type);
|
||||
return typeAsAwaitable.awaitedTypeOfType = type;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35161,7 +35172,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;
|
||||
}
|
||||
}
|
||||
@@ -35214,7 +35225,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 */
|
||||
@@ -37495,7 +37506,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;
|
||||
}
|
||||
|
||||
@@ -37539,7 +37550,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
|
||||
|
||||
@@ -47,6 +47,22 @@ tests/cases/compiler/awaitedTypeStrictNull.ts(22,12): error TS2589: Type instant
|
||||
])
|
||||
}
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/45924
|
||||
class Api<D = {}> {
|
||||
// Should result in `Promise<T>` instead of `Promise<Awaited<T>>`.
|
||||
async post<T = D>() { return this.request<T>(); }
|
||||
async request<D>(): Promise<D> { throw new Error(); }
|
||||
}
|
||||
|
||||
declare const api: Api;
|
||||
interface Obj { x: number }
|
||||
|
||||
async function fn<T>(): Promise<T extends object ? { [K in keyof T]: Obj } : Obj> {
|
||||
// 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 extends TExpected, TExpected> = TActual;
|
||||
|
||||
@@ -39,6 +39,22 @@ async function main() {
|
||||
])
|
||||
}
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/45924
|
||||
class Api<D = {}> {
|
||||
// Should result in `Promise<T>` instead of `Promise<Awaited<T>>`.
|
||||
async post<T = D>() { return this.request<T>(); }
|
||||
async request<D>(): Promise<D> { throw new Error(); }
|
||||
}
|
||||
|
||||
declare const api: Api;
|
||||
interface Obj { x: number }
|
||||
|
||||
async function fn<T>(): Promise<T extends object ? { [K in keyof T]: Obj } : Obj> {
|
||||
// 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 extends TExpected, TExpected> = TActual;
|
||||
|
||||
@@ -56,3 +72,14 @@ async function main() {
|
||||
MaybePromise(true),
|
||||
]);
|
||||
}
|
||||
// https://github.com/microsoft/TypeScript/issues/45924
|
||||
class Api {
|
||||
// Should result in `Promise<T>` instead of `Promise<Awaited<T>>`.
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -60,21 +60,21 @@ type T12 = Awaited<Promise<Promise<number>>>;
|
||||
|
||||
type T13 = _Expect<Awaited<Promise<Promise<number>> | 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<Awaited<Promise<Promise<number>> | 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<Awaited<Promise<Promise<number>> | 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<D = {}> {
|
||||
>Api : Symbol(Api, Decl(awaitedTypeStrictNull.ts, 38, 1))
|
||||
>D : Symbol(D, Decl(awaitedTypeStrictNull.ts, 41, 10))
|
||||
|
||||
// Should result in `Promise<T>` instead of `Promise<Awaited<T>>`.
|
||||
async post<T = D>() { return this.request<T>(); }
|
||||
>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<D>(): Promise<D> { 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<T>(): Promise<T extends object ? { [K in keyof T]: Obj } : Obj> {
|
||||
>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 extends TExpected, TExpected> = 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))
|
||||
|
||||
|
||||
@@ -128,6 +128,42 @@ async function main() {
|
||||
])
|
||||
}
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/45924
|
||||
class Api<D = {}> {
|
||||
>Api : Api<D>
|
||||
|
||||
// Should result in `Promise<T>` instead of `Promise<Awaited<T>>`.
|
||||
async post<T = D>() { return this.request<T>(); }
|
||||
>post : <T = D>() => Promise<T>
|
||||
>this.request<T>() : Promise<T>
|
||||
>this.request : <D>() => Promise<D>
|
||||
>this : this
|
||||
>request : <D>() => Promise<D>
|
||||
|
||||
async request<D>(): Promise<D> { throw new Error(); }
|
||||
>request : <D>() => Promise<D>
|
||||
>new Error() : Error
|
||||
>Error : ErrorConstructor
|
||||
}
|
||||
|
||||
declare const api: Api;
|
||||
>api : Api<{}>
|
||||
|
||||
interface Obj { x: number }
|
||||
>x : number
|
||||
|
||||
async function fn<T>(): Promise<T extends object ? { [K in keyof T]: Obj } : Obj> {
|
||||
>fn : <T>() => Promise<T extends object ? { [K in keyof T]: Obj; } : Obj>
|
||||
|
||||
// Per #45924, this was failing due to incorrect inference both above and here.
|
||||
// Should not error.
|
||||
return api.post();
|
||||
>api.post() : Promise<T extends object ? { [K in keyof T]: Obj; } : Obj>
|
||||
>api.post : <T = {}>() => Promise<T>
|
||||
>api : Api<{}>
|
||||
>post : <T = {}>() => Promise<T>
|
||||
}
|
||||
|
||||
// helps with tests where '.types' just prints out the type alias name
|
||||
type _Expect<TActual extends TExpected, TExpected> = TActual;
|
||||
>_Expect : TActual
|
||||
|
||||
@@ -41,5 +41,21 @@ async function main() {
|
||||
])
|
||||
}
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/45924
|
||||
class Api<D = {}> {
|
||||
// Should result in `Promise<T>` instead of `Promise<Awaited<T>>`.
|
||||
async post<T = D>() { return this.request<T>(); }
|
||||
async request<D>(): Promise<D> { throw new Error(); }
|
||||
}
|
||||
|
||||
declare const api: Api;
|
||||
interface Obj { x: number }
|
||||
|
||||
async function fn<T>(): Promise<T extends object ? { [K in keyof T]: Obj } : Obj> {
|
||||
// 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 extends TExpected, TExpected> = TActual;
|
||||
|
||||
Reference in New Issue
Block a user