From 96095efa2d63cac79c46d1e07379a9f08b9a711f Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Mon, 1 Feb 2021 18:00:38 -0800 Subject: [PATCH] Don't throw away results if there are multiple discriminants. --- src/compiler/checker.ts | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6b9dceed52d..29f87eb8a21 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -18988,9 +18988,15 @@ namespace ts { findMostOverlappyType(source, target); } - function discriminateTypeByDiscriminableItems(target: UnionType, discriminators: [() => Type, __String][], related: (source: Type, target: Type) => boolean | Ternary, defaultValue?: undefined, skipPartial?: boolean): Type | undefined; - function discriminateTypeByDiscriminableItems(target: UnionType, discriminators: [() => Type, __String][], related: (source: Type, target: Type) => boolean | Ternary, defaultValue: Type, skipPartial?: boolean): Type; - function discriminateTypeByDiscriminableItems(target: UnionType, discriminators: [() => Type, __String][], related: (source: Type, target: Type) => boolean | Ternary, defaultValue?: Type, skipPartial?: boolean) { + function discriminateTypeByDiscriminableItems(target: UnionType, discriminators: [() => Type, __String][], related: (source: Type, target: Type) => boolean | Ternary, defaultValue?: undefined, skipPartial?: boolean, allowMultiples?: boolean): Type | undefined; + function discriminateTypeByDiscriminableItems(target: UnionType, discriminators: [() => Type, __String][], related: (source: Type, target: Type) => boolean | Ternary, defaultValue: Type, skipPartial?: boolean, allowMultiples?: boolean): Type; + function discriminateTypeByDiscriminableItems( + target: UnionType, + discriminators: [() => Type, __String][], + related: (source: Type, target: Type) => boolean | Ternary, + defaultValue?: Type, + skipPartial?: boolean, + allowMultiples?: boolean) { // undefined=unknown, true=discriminated, false=not discriminated // The state of each type progresses from left to right. Discriminated types stop at 'true'. const discriminable = target.types.map(_ => undefined) as (boolean | undefined)[]; @@ -19015,13 +19021,16 @@ namespace ts { if (match === -1) { return defaultValue; } + // make sure exactly 1 matches before returning it - let nextMatch = discriminable.indexOf(/*searchElement*/ true, match + 1); - while (nextMatch !== -1) { - if (!isTypeIdenticalTo(target.types[match], target.types[nextMatch])) { - return defaultValue; + if (!allowMultiples) { + let nextMatch = discriminable.indexOf(/*searchElement*/ true, match + 1); + while (nextMatch !== -1) { + if (!isTypeIdenticalTo(target.types[match], target.types[nextMatch])) { + return defaultValue; + } + nextMatch = discriminable.indexOf(/*searchElement*/ true, nextMatch + 1); } - nextMatch = discriminable.indexOf(/*searchElement*/ true, nextMatch + 1); } return target.types[match]; } @@ -41039,10 +41048,11 @@ namespace ts { if (sourcePropertiesFiltered) { return discriminateTypeByDiscriminableItems( target, - map(sourcePropertiesFiltered, p => ([() => getTypeOfSymbol(p), p.escapedName])), - isRelatedTo, /*defaultValue*/ undefined, - skipPartial - ); + map(sourcePropertiesFiltered, p => [() => getTypeOfSymbol(p), p.escapedName]), + isRelatedTo, + /*defaultValue*/ undefined, + skipPartial, + /**/ true); } } }