@@ -18458,10 +18458,16 @@ namespace ts {
18458
18458
return getPromisedTypeOfPromise(promiseType) === promisedType;
18459
18459
}
18460
18460
18461
+ function isUserDefinedPromiseType(type: Type) {
18462
+ return !isReferenceToGlobalPromiseType(type) && !!getPromisedTypeOfPromise(type);
18463
+ }
18464
+
18461
18465
function inferToMultipleTypes(source: Type, targets: Type[], targetFlags: TypeFlags) {
18462
18466
let typeVariableCount = 0;
18463
18467
if (targetFlags & TypeFlags.Union) {
18464
18468
let nakedTypeVariable: Type | undefined;
18469
+ let remainderArePromises = false;
18470
+ const sources = source.flags & TypeFlags.Union ? (<UnionType>source).types : [source];
18465
18471
for (const t of targets) {
18466
18472
if (getInferenceInfoForType(t)) {
18467
18473
nakedTypeVariable = t;
@@ -18470,11 +18476,13 @@ namespace ts {
18470
18476
}
18471
18477
18472
18478
// To better handle inference for `Promise`-like types, we detect a target union of `T | PromiseLike<T>`
18473
- // (for any compatible `PromiseLike`). When encountered, we infer from source to the type parameter `T`,
18474
- // where each type of source is mapped to extract the promised type of any promise (e.g.,
18475
- // `string | Promise<number>` becomes `string | number`).
18479
+ // (for any compatible `PromiseLike`). When encountered, we infer all promise-like sources to the promise-like
18480
+ // targets and all non-promise-like sources to the naked type variable. For example when inferring to
18481
+ // `T | PromiseLike<T>` from `number | boolean | Promise<string>`, we infer to `PromiseLike<T>` from
18482
+ // `Promise<string>` and to `T` for `number | boolean`. We allow for multiple promise-like types in target
18483
+ // to better support JQuery's `PromiseBase` which returns something like
18484
+ // `PromiseBase<T, U, V...> | PromiseLike<T> | T` in its fulfillment callbacks.
18476
18485
if (typeVariableCount === 1) {
18477
- let remainderArePromises = false;
18478
18486
for (const t of targets) {
18479
18487
if (!getInferenceInfoForType(t)) {
18480
18488
if (isPromiseForType(t, nakedTypeVariable!)) {
@@ -18486,14 +18494,8 @@ namespace ts {
18486
18494
}
18487
18495
}
18488
18496
}
18489
- // remaining constituents are promise-like types whose "promised types" are `T`
18490
- if (remainderArePromises) {
18491
- inferFromTypes(mapType(source, s => getPromisedTypeOfPromise(s) ?? s), nakedTypeVariable!);
18492
- return;
18493
- }
18494
18497
}
18495
18498
18496
- const sources = source.flags & TypeFlags.Union ? (<UnionType>source).types : [source];
18497
18499
const matched = new Array<boolean>(sources.length);
18498
18500
let inferenceCircularity = false;
18499
18501
// First infer to types that are not naked type variables. For each source type we
@@ -18503,12 +18505,24 @@ namespace ts {
18503
18505
for (const t of targets) {
18504
18506
if (!getInferenceInfoForType(t)) {
18505
18507
for (let i = 0; i < sources.length; i++) {
18506
- const saveInferencePriority = inferencePriority;
18507
- inferencePriority = InferencePriority.MaxValue;
18508
- inferFromTypes(sources[i], t);
18509
- if (inferencePriority === priority) matched[i] = true;
18510
- inferenceCircularity = inferenceCircularity || inferencePriority === InferencePriority.Circularity;
18511
- inferencePriority = Math.min(inferencePriority, saveInferencePriority);
18508
+ // When inferring to a union consisting solely of `T` and promise-like constituents,
18509
+ // we infer only custom promise-like sources to promise-like constituents so that we can
18510
+ // capture inferences to other type arguments. We skip sources with references to the
18511
+ // global `Promise<T>` and `PromiseLike<T>` types as we can infer the promised types
18512
+ // of those directly to the type variable, below.
18513
+ if (!remainderArePromises || isUserDefinedPromiseType(sources[i])) {
18514
+ const saveInferencePriority = inferencePriority;
18515
+ inferencePriority = InferencePriority.MaxValue;
18516
+ // When inferring to a union of `T | PromiseLike<T>`, we will first
18517
+ // infer a promise-like source to a promise-like target, but we will
18518
+ // also infer the promised type directly to the type variable.
18519
+ inferFromTypes(sources[i], t);
18520
+ if (inferencePriority === priority && !remainderArePromises) {
18521
+ matched[i] = true;
18522
+ }
18523
+ inferenceCircularity = inferenceCircularity || inferencePriority === InferencePriority.Circularity;
18524
+ inferencePriority = Math.min(inferencePriority, saveInferencePriority);
18525
+ }
18512
18526
}
18513
18527
}
18514
18528
}
@@ -18527,7 +18541,10 @@ namespace ts {
18527
18541
// types from which no inferences have been made so far and infer from that union to the
18528
18542
// naked type variable.
18529
18543
if (typeVariableCount === 1 && !inferenceCircularity) {
18530
- const unmatched = flatMap(sources, (s, i) => matched[i] ? undefined : s);
18544
+ const unmatched = mapDefined(sources, (s, i) =>
18545
+ matched[i] ? undefined :
18546
+ remainderArePromises ? getPromisedTypeOfPromise(s) ?? s :
18547
+ s);
18531
18548
if (unmatched.length) {
18532
18549
inferFromTypes(getUnionType(unmatched), nakedTypeVariable!);
18533
18550
return;
@@ -30147,6 +30164,11 @@ namespace ts {
30147
30164
return promisedType && getAwaitedType(promisedType, errorNode, diagnosticMessage, arg0);
30148
30165
}
30149
30166
30167
+ function isReferenceToGlobalPromiseType(type: Type) {
30168
+ return isReferenceToType(type, getGlobalPromiseType(/*reportErrors*/ false))
30169
+ || isReferenceToType(type, getGlobalPromiseLikeType(/*reportErrors*/ false));
30170
+ }
30171
+
30150
30172
/**
30151
30173
* Gets the "promised type" of a promise.
30152
30174
* @param type The type of the promise.
@@ -30172,8 +30194,7 @@ namespace ts {
30172
30194
return typeAsPromise.promisedTypeOfPromise;
30173
30195
}
30174
30196
30175
- if (isReferenceToType(type, getGlobalPromiseType(/*reportErrors*/ false)) ||
30176
- isReferenceToType(type, getGlobalPromiseLikeType(/*reportErrors*/ false))) {
30197
+ if (isReferenceToGlobalPromiseType(type)) {
30177
30198
return typeAsPromise.promisedTypeOfPromise = getTypeArguments(<GenericType>type)[0];
30178
30199
}
30179
30200
0 commit comments