@@ -18462,6 +18462,8 @@ namespace ts {
18462
18462
let typeVariableCount = 0;
18463
18463
if (targetFlags & TypeFlags.Union) {
18464
18464
let nakedTypeVariable: Type | undefined;
18465
+ let remainderArePromises = false;
18466
+ const sources = source.flags & TypeFlags.Union ? (<UnionType>source).types : [source];
18465
18467
for (const t of targets) {
18466
18468
if (getInferenceInfoForType(t)) {
18467
18469
nakedTypeVariable = t;
@@ -18470,11 +18472,13 @@ namespace ts {
18470
18472
}
18471
18473
18472
18474
// 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`).
18475
+ // (for any compatible `PromiseLike`). When encountered, we infer all promise-like sources to the promise-like
18476
+ // targets and all non-promise-like sources to the naked type variable. For example when inferring to
18477
+ // `T | PromiseLike<T>` from `number | boolean | Promise<string>`, we infer to `PromiseLike<T>` from
18478
+ // `Promise<string>` and to `T` for `number | boolean`. We allow for multiple promise-like types in target
18479
+ // to better support JQuery's `PromiseBase` which returns something like
18480
+ // `PromiseBase<T, U, V...> | PromiseLike<T> | T` in its fulfillment callbacks.
18476
18481
if (typeVariableCount === 1) {
18477
- let remainderArePromises = false;
18478
18482
for (const t of targets) {
18479
18483
if (!getInferenceInfoForType(t)) {
18480
18484
if (isPromiseForType(t, nakedTypeVariable!)) {
@@ -18486,14 +18490,8 @@ namespace ts {
18486
18490
}
18487
18491
}
18488
18492
}
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
18493
}
18495
18494
18496
- const sources = source.flags & TypeFlags.Union ? (<UnionType>source).types : [source];
18497
18495
const matched = new Array<boolean>(sources.length);
18498
18496
let inferenceCircularity = false;
18499
18497
// First infer to types that are not naked type variables. For each source type we
@@ -18503,12 +18501,28 @@ namespace ts {
18503
18501
for (const t of targets) {
18504
18502
if (!getInferenceInfoForType(t)) {
18505
18503
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);
18504
+ // When inferring to a union consisting solely `T` and promise-like constituents,
18505
+ // we infer only promise-like sources to promise-like constituents.
18506
+ let promisedType: Type | undefined;
18507
+ if (!remainderArePromises || (promisedType = getPromisedTypeOfPromise(sources[i]))) {
18508
+ const saveInferencePriority = inferencePriority;
18509
+ inferencePriority = InferencePriority.MaxValue;
18510
+ // When inferring to a union of `T | PromiseLike<T>`, we will first
18511
+ // infer a promise-like source to a promise-like target, but we will
18512
+ // also infer the promised type directly to the type variable.
18513
+ inferFromTypes(sources[i], t);
18514
+ if (inferencePriority === priority) {
18515
+ if (promisedType) {
18516
+ sources[i] = promisedType;
18517
+ matched[i] = false;
18518
+ }
18519
+ else {
18520
+ matched[i] = true;
18521
+ }
18522
+ }
18523
+ inferenceCircularity = inferenceCircularity || inferencePriority === InferencePriority.Circularity;
18524
+ inferencePriority = Math.min(inferencePriority, saveInferencePriority);
18525
+ }
18512
18526
}
18513
18527
}
18514
18528
}
@@ -18527,7 +18541,7 @@ 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) => matched[i] ? undefined : s);
18531
18545
if (unmatched.length) {
18532
18546
inferFromTypes(getUnionType(unmatched), nakedTypeVariable!);
18533
18547
return;
0 commit comments