Skip to content

Commit 8eba362

Browse files
committed
Fix for relating covered discriminants in unions
1 parent a60feb2 commit 8eba362

File tree

6 files changed

+104
-4
lines changed

6 files changed

+104
-4
lines changed

src/compiler/checker.ts

+15-1
Original file line numberDiff line numberDiff line change
@@ -17273,7 +17273,11 @@ namespace ts {
1727317273
result &= signaturesRelatedTo(source, type, SignatureKind.Construct, /*reportStructuralErrors*/ false);
1727417274
if (result) {
1727517275
result &= indexTypesRelatedTo(source, type, IndexKind.String, /*sourceIsPrimitive*/ false, /*reportStructuralErrors*/ false, IntersectionState.None);
17276-
if (result) {
17276+
// Comparing numeric index types when both `source` and `type` are tuples is unnecessary as the
17277+
// element types should be sufficiently covered by `propertiesRelatedTo`. It also causes problems
17278+
// with index type assignability as the types for the excluded discriminants are still included
17279+
// in the index type.
17280+
if (result && !(isTupleType(source) && isTupleType(type))) {
1727717281
result &= indexTypesRelatedTo(source, type, IndexKind.Number, /*sourceIsPrimitive*/ false, /*reportStructuralErrors*/ false, IntersectionState.None);
1727817282
}
1727917283
}
@@ -17498,6 +17502,7 @@ namespace ts {
1749817502
for (let i = 0; i < maxArity; i++) {
1749917503
const targetFlags = i < targetArity ? target.target.elementFlags[i] : targetRestFlag;
1750017504
const sourceFlags = isTupleType(source) && i < sourceArity ? source.target.elementFlags[i] : sourceRestFlag;
17505+
let canExcludeDiscriminants = !!excludedProperties;
1750117506
if (sourceFlags && targetFlags) {
1750217507
if (targetFlags & ElementFlags.Variadic && !(sourceFlags & ElementFlags.Variadic) ||
1750317508
(sourceFlags & ElementFlags.Variadic && !(targetFlags & ElementFlags.Variable))) {
@@ -17514,6 +17519,15 @@ namespace ts {
1751417519
return Ternary.False;
1751517520
}
1751617521
}
17522+
// We can only exclude discriminant properties if we have not yet encountered a variable-length element.
17523+
if (canExcludeDiscriminants) {
17524+
if (sourceFlags & ElementFlags.Variable || targetFlags & ElementFlags.Variable) {
17525+
canExcludeDiscriminants = false;
17526+
}
17527+
if (canExcludeDiscriminants && excludedProperties?.has(("" + i) as __String)) {
17528+
continue;
17529+
}
17530+
}
1751717531
const sourceType = getTypeArguments(source)[Math.min(i, sourceArity - 1)];
1751817532
const targetType = getTypeArguments(target)[Math.min(i, targetArity - 1)];
1751917533
const targetCheckType = sourceFlags & ElementFlags.Variadic && targetFlags & ElementFlags.Rest ? createArrayType(targetType) : targetType;

tests/baselines/reference/assignmentCompatWithDiscriminatedUnion.errors.txt

+10-1
Original file line numberDiff line numberDiff line change
@@ -221,4 +221,13 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
221221
type: obj1.type
222222
};
223223
}
224-
}
224+
}
225+
226+
// https://github.com/microsoft/TypeScript/issues/39357
227+
namespace GH39357 {
228+
type A = ["a", number] | ["b", number] | ["c", string];
229+
type B = "a" | "b" | "c";
230+
declare const b: B;
231+
const a: A = b === "a" || b === "b" ? [b, 1] : ["c", ""];
232+
}
233+

tests/baselines/reference/assignmentCompatWithDiscriminatedUnion.js

+15-1
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,16 @@ namespace GH20889 {
191191
type: obj1.type
192192
};
193193
}
194-
}
194+
}
195+
196+
// https://github.com/microsoft/TypeScript/issues/39357
197+
namespace GH39357 {
198+
type A = ["a", number] | ["b", number] | ["c", string];
199+
type B = "a" | "b" | "c";
200+
declare const b: B;
201+
const a: A = b === "a" || b === "b" ? [b, 1] : ["c", ""];
202+
}
203+
195204

196205
//// [assignmentCompatWithDiscriminatedUnion.js]
197206
// see 'typeRelatedToDiscriminatedType' in checker.ts:
@@ -289,3 +298,8 @@ var GH20889;
289298
};
290299
}
291300
})(GH20889 || (GH20889 = {}));
301+
// https://github.com/microsoft/TypeScript/issues/39357
302+
var GH39357;
303+
(function (GH39357) {
304+
var a = b === "a" || b === "b" ? [b, 1] : ["c", ""];
305+
})(GH39357 || (GH39357 = {}));

tests/baselines/reference/assignmentCompatWithDiscriminatedUnion.symbols

+23
Original file line numberDiff line numberDiff line change
@@ -492,3 +492,26 @@ namespace GH20889 {
492492
};
493493
}
494494
}
495+
496+
// https://github.com/microsoft/TypeScript/issues/39357
497+
namespace GH39357 {
498+
>GH39357 : Symbol(GH39357, Decl(assignmentCompatWithDiscriminatedUnion.ts, 192, 1))
499+
500+
type A = ["a", number] | ["b", number] | ["c", string];
501+
>A : Symbol(A, Decl(assignmentCompatWithDiscriminatedUnion.ts, 195, 19))
502+
503+
type B = "a" | "b" | "c";
504+
>B : Symbol(B, Decl(assignmentCompatWithDiscriminatedUnion.ts, 196, 59))
505+
506+
declare const b: B;
507+
>b : Symbol(b, Decl(assignmentCompatWithDiscriminatedUnion.ts, 198, 17))
508+
>B : Symbol(B, Decl(assignmentCompatWithDiscriminatedUnion.ts, 196, 59))
509+
510+
const a: A = b === "a" || b === "b" ? [b, 1] : ["c", ""];
511+
>a : Symbol(a, Decl(assignmentCompatWithDiscriminatedUnion.ts, 199, 9))
512+
>A : Symbol(A, Decl(assignmentCompatWithDiscriminatedUnion.ts, 195, 19))
513+
>b : Symbol(b, Decl(assignmentCompatWithDiscriminatedUnion.ts, 198, 17))
514+
>b : Symbol(b, Decl(assignmentCompatWithDiscriminatedUnion.ts, 198, 17))
515+
>b : Symbol(b, Decl(assignmentCompatWithDiscriminatedUnion.ts, 198, 17))
516+
}
517+

tests/baselines/reference/assignmentCompatWithDiscriminatedUnion.types

+32
Original file line numberDiff line numberDiff line change
@@ -464,3 +464,35 @@ namespace GH20889 {
464464
};
465465
}
466466
}
467+
468+
// https://github.com/microsoft/TypeScript/issues/39357
469+
namespace GH39357 {
470+
>GH39357 : typeof GH39357
471+
472+
type A = ["a", number] | ["b", number] | ["c", string];
473+
>A : A
474+
475+
type B = "a" | "b" | "c";
476+
>B : "a" | "b" | "c"
477+
478+
declare const b: B;
479+
>b : "a" | "b" | "c"
480+
481+
const a: A = b === "a" || b === "b" ? [b, 1] : ["c", ""];
482+
>a : A
483+
>b === "a" || b === "b" ? [b, 1] : ["c", ""] : ["a" | "b", number] | ["c", string]
484+
>b === "a" || b === "b" : boolean
485+
>b === "a" : boolean
486+
>b : "a" | "b" | "c"
487+
>"a" : "a"
488+
>b === "b" : boolean
489+
>b : "b" | "c"
490+
>"b" : "b"
491+
>[b, 1] : ["a" | "b", number]
492+
>b : "a" | "b"
493+
>1 : 1
494+
>["c", ""] : ["c", string]
495+
>"c" : "c"
496+
>"" : ""
497+
}
498+

tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithDiscriminatedUnion.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -190,4 +190,12 @@ namespace GH20889 {
190190
type: obj1.type
191191
};
192192
}
193-
}
193+
}
194+
195+
// https://github.com/microsoft/TypeScript/issues/39357
196+
namespace GH39357 {
197+
type A = ["a", number] | ["b", number] | ["c", string];
198+
type B = "a" | "b" | "c";
199+
declare const b: B;
200+
const a: A = b === "a" || b === "b" ? [b, 1] : ["c", ""];
201+
}

0 commit comments

Comments
 (0)