Skip to content

Commit 3f053ca

Browse files
committed
Allow identical discriminants when discriminating, rather than trying to unify identical union members
1 parent aa9eed6 commit 3f053ca

File tree

3 files changed

+21
-40
lines changed

3 files changed

+21
-40
lines changed

src/compiler/checker.ts

Lines changed: 13 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -12972,26 +12972,6 @@ namespace ts {
1297212972
return true;
1297312973
}
1297412974

12975-
function removeStructurallyIdenticalTypes(types: Type[]): void {
12976-
const len = types.length;
12977-
if (len === 0 || isSetOfLiteralsFromSameEnum(types)) {
12978-
return;
12979-
}
12980-
let i = len;
12981-
while (i > 0) {
12982-
i--;
12983-
const source = types[i];
12984-
for (const target of types) {
12985-
if (source !== target) {
12986-
if (isTypeIdenticalTo(source, target)) {
12987-
orderedRemoveItemAt(types, i);
12988-
break;
12989-
}
12990-
}
12991-
}
12992-
}
12993-
}
12994-
1299512975
function removeRedundantLiteralTypes(types: Type[], includes: TypeFlags) {
1299612976
let i = types.length;
1299712977
while (i > 0) {
@@ -13026,7 +13006,7 @@ namespace ts {
1302613006
const typeSet: Type[] = [];
1302713007
const includes = addTypesToUnion(typeSet, 0, types);
1302813008
if (unionReduction !== UnionReduction.None) {
13029-
if (includes & TypeFlags.AnyOrUnknown && unionReduction !== UnionReduction.Exact) {
13009+
if (includes & TypeFlags.AnyOrUnknown) {
1303013010
return includes & TypeFlags.Any ? includes & TypeFlags.IncludesWildcard ? wildcardType : anyType : unknownType;
1303113011
}
1303213012
switch (unionReduction) {
@@ -13040,9 +13020,6 @@ namespace ts {
1304013020
return errorType;
1304113021
}
1304213022
break;
13043-
case UnionReduction.Exact:
13044-
removeStructurallyIdenticalTypes(typeSet);
13045-
break;
1304613023
}
1304713024
if (typeSet.length === 0) {
1304813025
return includes & TypeFlags.Null ? includes & TypeFlags.IncludesNonWideningType ? nullType : nullWideningType :
@@ -18266,11 +18243,6 @@ namespace ts {
1826618243
function discriminateTypeByDiscriminableItems(target: UnionType, discriminators: [() => Type, __String][], related: (source: Type, target: Type) => boolean | Ternary, defaultValue?: undefined, skipPartial?: boolean): Type | undefined;
1826718244
function discriminateTypeByDiscriminableItems(target: UnionType, discriminators: [() => Type, __String][], related: (source: Type, target: Type) => boolean | Ternary, defaultValue: Type, skipPartial?: boolean): Type;
1826818245
function discriminateTypeByDiscriminableItems(target: UnionType, discriminators: [() => Type, __String][], related: (source: Type, target: Type) => boolean | Ternary, defaultValue?: Type, skipPartial?: boolean) {
18269-
const reduced = getUnionType(target.types, UnionReduction.Exact, target.aliasSymbol, target.aliasTypeArguments);
18270-
if (!(reduced.flags & TypeFlags.Union)) {
18271-
return reduced;
18272-
}
18273-
target = reduced as UnionType;
1827418246
// undefined=unknown, true=discriminated, false=not discriminated
1827518247
// The state of each type progresses from left to right. Discriminated types stop at 'true'.
1827618248
const discriminable = target.types.map(_ => undefined) as (boolean | undefined)[];
@@ -18291,9 +18263,19 @@ namespace ts {
1829118263
i++;
1829218264
}
1829318265
}
18294-
const match = discriminable.indexOf(/*searchElement*/ true);
18266+
let match = discriminable.indexOf(/*searchElement*/ true);
18267+
if (match === -1) {
18268+
return defaultValue;
18269+
}
1829518270
// make sure exactly 1 matches before returning it
18296-
return match === -1 || discriminable.indexOf(/*searchElement*/ true, match + 1) !== -1 ? defaultValue : target.types[match];
18271+
let nextMatch = discriminable.indexOf(/*searchElement*/ true, match + 1);
18272+
while (nextMatch !== -1) {
18273+
if (!isTypeIdenticalTo(target.types[match], target.types[nextMatch])) {
18274+
return defaultValue;
18275+
}
18276+
nextMatch = discriminable.indexOf(/*searchElement*/ true, nextMatch + 1);
18277+
}
18278+
return target.types[match];
1829718279
}
1829818280

1829918281
/**

src/compiler/types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4185,7 +4185,6 @@ namespace ts {
41854185
None = 0,
41864186
Literal,
41874187
Subtype,
4188-
Exact,
41894188
}
41904189

41914190
/* @internal */

tests/baselines/reference/contextualTypeWithUnionTypeObjectLiteral.errors.txt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ tests/cases/conformance/types/union/contextualTypeWithUnionTypeObjectLiteral.ts(
2323
Types of property 'prop' are incompatible.
2424
Type 'string | number' is not assignable to type 'number'.
2525
Type 'string' is not assignable to type 'number'.
26-
tests/cases/conformance/types/union/contextualTypeWithUnionTypeObjectLiteral.ts(58,5): error TS2322: Type '(a: string, b: number) => string | number' is not assignable to type '((a: string, b: number) => number) | ((a: string, b: number) => string)'.
27-
Type '(a: string, b: number) => string | number' is not assignable to type '(a: string, b: number) => number'.
28-
Type 'string | number' is not assignable to type 'number'.
29-
Type 'string' is not assignable to type 'number'.
26+
tests/cases/conformance/types/union/contextualTypeWithUnionTypeObjectLiteral.ts(58,5): error TS2322: Type '(a: string, b: number) => string | number' is not assignable to type '((a: string, b: number) => string) | ((a: string, b: number) => number)'.
27+
Type '(a: string, b: number) => string | number' is not assignable to type '(a: string, b: number) => string'.
28+
Type 'string | number' is not assignable to type 'string'.
29+
Type 'number' is not assignable to type 'string'.
3030

3131

3232
==== tests/cases/conformance/types/union/contextualTypeWithUnionTypeObjectLiteral.ts (6 errors) ====
@@ -119,9 +119,9 @@ tests/cases/conformance/types/union/contextualTypeWithUnionTypeObjectLiteral.ts(
119119
var i11Ori21: I11 | I21 = { // Like i1 and i2 both
120120
commonMethodDifferentReturnType: (a, b) => strOrNumber,
121121
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
122-
!!! error TS2322: Type '(a: string, b: number) => string | number' is not assignable to type '((a: string, b: number) => number) | ((a: string, b: number) => string)'.
123-
!!! error TS2322: Type '(a: string, b: number) => string | number' is not assignable to type '(a: string, b: number) => number'.
124-
!!! error TS2322: Type 'string | number' is not assignable to type 'number'.
125-
!!! error TS2322: Type 'string' is not assignable to type 'number'.
122+
!!! error TS2322: Type '(a: string, b: number) => string | number' is not assignable to type '((a: string, b: number) => string) | ((a: string, b: number) => number)'.
123+
!!! error TS2322: Type '(a: string, b: number) => string | number' is not assignable to type '(a: string, b: number) => string'.
124+
!!! error TS2322: Type 'string | number' is not assignable to type 'string'.
125+
!!! error TS2322: Type 'number' is not assignable to type 'string'.
126126
!!! related TS6500 tests/cases/conformance/types/union/contextualTypeWithUnionTypeObjectLiteral.ts:35:5: The expected type comes from property 'commonMethodDifferentReturnType' which is declared here on type 'I11 | I21'
127127
};

0 commit comments

Comments
 (0)