mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-09 07:21:18 -05:00
Fix for Awaited<T> inference (#49748)
This commit is contained in:
@@ -36601,6 +36601,37 @@ m2: ${(this.mapper2 as unknown as DebugTypeMapper).__debugToString().split("\n")
|
||||
type;
|
||||
}
|
||||
|
||||
function isAwaitedTypeNeeded(type: Type) {
|
||||
// If this is already an `Awaited<T>`, we shouldn't wrap it. This helps to avoid `Awaited<Awaited<T>>` in higher-order.
|
||||
if (isTypeAny(type) || isAwaitedTypeInstantiation(type)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We only need `Awaited<T>` if `T` contains possibly non-primitive types.
|
||||
if (isGenericObjectType(type)) {
|
||||
const baseConstraint = getBaseConstraintOfType(type);
|
||||
// We only need `Awaited<T>` if `T` has no base constraint, or the base constraint of `T` is `any`, `unknown`, `{}`, `object`,
|
||||
// or is promise-like.
|
||||
if (!baseConstraint || (baseConstraint.flags & TypeFlags.AnyOrUnknown) || isEmptyObjectType(baseConstraint) || isThenableType(baseConstraint)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function tryCreateAwaitedType(type: Type): Type | undefined {
|
||||
// Nothing to do if `Awaited<T>` doesn't exist
|
||||
const awaitedSymbol = getGlobalAwaitedSymbol(/*reportErrors*/ true);
|
||||
if (awaitedSymbol) {
|
||||
// Unwrap unions that may contain `Awaited<T>`, otherwise its possible to manufacture an `Awaited<Awaited<T> | U>` where
|
||||
// an `Awaited<T | U>` would suffice.
|
||||
return getTypeAliasInstantiation(awaitedSymbol, [unwrapAwaitedType(type)]);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function createAwaitedTypeIfNeeded(type: Type): Type {
|
||||
// We wrap type `T` in `Awaited<T>` based on the following conditions:
|
||||
// - `T` is not already an `Awaited<U>`, and
|
||||
@@ -36610,28 +36641,10 @@ m2: ${(this.mapper2 as unknown as DebugTypeMapper).__debugToString().split("\n")
|
||||
// - The base constraint of `T` is `any`, `unknown`, `object`, or `{}`, or
|
||||
// - The base constraint of `T` is an object type with a callable `then` method.
|
||||
|
||||
if (isTypeAny(type)) {
|
||||
return type;
|
||||
}
|
||||
|
||||
// If this is already an `Awaited<T>`, just return it. This helps to avoid `Awaited<Awaited<T>>` in higher-order.
|
||||
if (isAwaitedTypeInstantiation(type)) {
|
||||
return type;
|
||||
}
|
||||
|
||||
// Only instantiate `Awaited<T>` if `T` contains possibly non-primitive types.
|
||||
if (isGenericObjectType(type)) {
|
||||
const baseConstraint = getBaseConstraintOfType(type);
|
||||
// Only instantiate `Awaited<T>` if `T` has no base constraint, or the base constraint of `T` is `any`, `unknown`, `{}`, `object`,
|
||||
// or is promise-like.
|
||||
if (!baseConstraint || (baseConstraint.flags & TypeFlags.AnyOrUnknown) || isEmptyObjectType(baseConstraint) || isThenableType(baseConstraint)) {
|
||||
// Nothing to do if `Awaited<T>` doesn't exist
|
||||
const awaitedSymbol = getGlobalAwaitedSymbol(/*reportErrors*/ true);
|
||||
if (awaitedSymbol) {
|
||||
// Unwrap unions that may contain `Awaited<T>`, otherwise its possible to manufacture an `Awaited<Awaited<T> | U>` where
|
||||
// an `Awaited<T | U>` would suffice.
|
||||
return getTypeAliasInstantiation(awaitedSymbol, [unwrapAwaitedType(type)]);
|
||||
}
|
||||
if (isAwaitedTypeNeeded(type)) {
|
||||
const awaitedType = tryCreateAwaitedType(type);
|
||||
if (awaitedType) {
|
||||
return awaitedType;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36693,6 +36706,11 @@ m2: ${(this.mapper2 as unknown as DebugTypeMapper).__debugToString().split("\n")
|
||||
return typeAsAwaitable.awaitedTypeOfType = mapped;
|
||||
}
|
||||
|
||||
// If `type` is generic and should be wrapped in `Awaited<T>`, return it.
|
||||
if (isAwaitedTypeNeeded(type)) {
|
||||
return typeAsAwaitable.awaitedTypeOfType = type;
|
||||
}
|
||||
|
||||
const thisTypeForErrorOut: { value: Type | undefined } = { value: undefined };
|
||||
const promisedType = getPromisedTypeOfPromise(type, /*errorNode*/ undefined, thisTypeForErrorOut);
|
||||
if (promisedType) {
|
||||
|
||||
@@ -168,4 +168,13 @@ tests/cases/compiler/awaitedType.ts(22,12): error TS2589: Type instantiation is
|
||||
|
||||
// helps with tests where '.types' just prints out the type alias name
|
||||
type _Expect<TActual extends TExpected, TExpected> = TActual;
|
||||
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/48320
|
||||
async function f17<T extends (...args: any[]) => Promise<any>>(fn: T) {
|
||||
const ret: Awaited<ReturnType<T>> = await fn(1, 2, 3);
|
||||
return ret;
|
||||
}
|
||||
async function f17_usage() {
|
||||
const x = await f17(async () => 123 as const);
|
||||
return { x };
|
||||
}
|
||||
@@ -160,7 +160,16 @@ async function f16<T extends number & { then(): void }>(x: T) {
|
||||
|
||||
// helps with tests where '.types' just prints out the type alias name
|
||||
type _Expect<TActual extends TExpected, TExpected> = TActual;
|
||||
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/48320
|
||||
async function f17<T extends (...args: any[]) => Promise<any>>(fn: T) {
|
||||
const ret: Awaited<ReturnType<T>> = await fn(1, 2, 3);
|
||||
return ret;
|
||||
}
|
||||
async function f17_usage() {
|
||||
const x = await f17(async () => 123 as const);
|
||||
return { x };
|
||||
}
|
||||
|
||||
//// [awaitedType.js]
|
||||
async function main() {
|
||||
@@ -263,3 +272,12 @@ async function f16(x) {
|
||||
// y: T
|
||||
const y = await x;
|
||||
}
|
||||
// https://github.com/microsoft/TypeScript/issues/48320
|
||||
async function f17(fn) {
|
||||
const ret = await fn(1, 2, 3);
|
||||
return ret;
|
||||
}
|
||||
async function f17_usage() {
|
||||
const x = await f17(async () => 123);
|
||||
return { x };
|
||||
}
|
||||
|
||||
@@ -403,3 +403,33 @@ type _Expect<TActual extends TExpected, TExpected> = TActual;
|
||||
>TExpected : Symbol(TExpected, Decl(awaitedType.ts, 160, 39))
|
||||
>TActual : Symbol(TActual, Decl(awaitedType.ts, 160, 13))
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/48320
|
||||
async function f17<T extends (...args: any[]) => Promise<any>>(fn: T) {
|
||||
>f17 : Symbol(f17, Decl(awaitedType.ts, 160, 61))
|
||||
>T : Symbol(T, Decl(awaitedType.ts, 163, 19))
|
||||
>args : Symbol(args, Decl(awaitedType.ts, 163, 30))
|
||||
>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, --, --))
|
||||
>fn : Symbol(fn, Decl(awaitedType.ts, 163, 63))
|
||||
>T : Symbol(T, Decl(awaitedType.ts, 163, 19))
|
||||
|
||||
const ret: Awaited<ReturnType<T>> = await fn(1, 2, 3);
|
||||
>ret : Symbol(ret, Decl(awaitedType.ts, 164, 9))
|
||||
>Awaited : Symbol(Awaited, Decl(lib.es5.d.ts, --, --))
|
||||
>ReturnType : Symbol(ReturnType, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(awaitedType.ts, 163, 19))
|
||||
>fn : Symbol(fn, Decl(awaitedType.ts, 163, 63))
|
||||
|
||||
return ret;
|
||||
>ret : Symbol(ret, Decl(awaitedType.ts, 164, 9))
|
||||
}
|
||||
async function f17_usage() {
|
||||
>f17_usage : Symbol(f17_usage, Decl(awaitedType.ts, 166, 1))
|
||||
|
||||
const x = await f17(async () => 123 as const);
|
||||
>x : Symbol(x, Decl(awaitedType.ts, 168, 9))
|
||||
>f17 : Symbol(f17, Decl(awaitedType.ts, 160, 61))
|
||||
>const : Symbol(const)
|
||||
|
||||
return { x };
|
||||
>x : Symbol(x, Decl(awaitedType.ts, 169, 12))
|
||||
}
|
||||
|
||||
@@ -278,8 +278,8 @@ async function f11<T extends { then(onfulfilled: (value: unknown) => void): void
|
||||
|
||||
// y: Awaited<T>
|
||||
const y = await x;
|
||||
>y : unknown
|
||||
>await x : unknown
|
||||
>y : Awaited<T>
|
||||
>await x : Awaited<T>
|
||||
>x : T
|
||||
}
|
||||
|
||||
@@ -358,3 +358,37 @@ async function f16<T extends number & { then(): void }>(x: T) {
|
||||
type _Expect<TActual extends TExpected, TExpected> = TActual;
|
||||
>_Expect : TActual
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/48320
|
||||
async function f17<T extends (...args: any[]) => Promise<any>>(fn: T) {
|
||||
>f17 : <T extends (...args: any[]) => Promise<any>>(fn: T) => Promise<ReturnType<T>>
|
||||
>args : any[]
|
||||
>fn : T
|
||||
|
||||
const ret: Awaited<ReturnType<T>> = await fn(1, 2, 3);
|
||||
>ret : Awaited<ReturnType<T>>
|
||||
>await fn(1, 2, 3) : any
|
||||
>fn(1, 2, 3) : Promise<any>
|
||||
>fn : T
|
||||
>1 : 1
|
||||
>2 : 2
|
||||
>3 : 3
|
||||
|
||||
return ret;
|
||||
>ret : Awaited<ReturnType<T>>
|
||||
}
|
||||
async function f17_usage() {
|
||||
>f17_usage : () => Promise<{ x: 123; }>
|
||||
|
||||
const x = await f17(async () => 123 as const);
|
||||
>x : 123
|
||||
>await f17(async () => 123 as const) : 123
|
||||
>f17(async () => 123 as const) : Promise<Promise<123>>
|
||||
>f17 : <T extends (...args: any[]) => Promise<any>>(fn: T) => Promise<ReturnType<T>>
|
||||
>async () => 123 as const : () => Promise<123>
|
||||
>123 as const : 123
|
||||
>123 : 123
|
||||
|
||||
return { x };
|
||||
>{ x } : { x: 123; }
|
||||
>x : 123
|
||||
}
|
||||
|
||||
@@ -162,3 +162,13 @@ async function f16<T extends number & { then(): void }>(x: T) {
|
||||
|
||||
// helps with tests where '.types' just prints out the type alias name
|
||||
type _Expect<TActual extends TExpected, TExpected> = TActual;
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/48320
|
||||
async function f17<T extends (...args: any[]) => Promise<any>>(fn: T) {
|
||||
const ret: Awaited<ReturnType<T>> = await fn(1, 2, 3);
|
||||
return ret;
|
||||
}
|
||||
async function f17_usage() {
|
||||
const x = await f17(async () => 123 as const);
|
||||
return { x };
|
||||
}
|
||||
Reference in New Issue
Block a user