From 2e68b7614bcab17a0f7d89fb9f513d4cdae997aa Mon Sep 17 00:00:00 2001
From: Anders Hejlsberg <andersh@microsoft.com>
Date: Sat, 22 Jun 2024 14:05:06 +0200
Subject: [PATCH 1/3] Handle partially overlapping discriminants

---
 src/compiler/checker.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index b7220fb89543d..4869380761e19 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -24177,7 +24177,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
             for (let i = 0; i < types.length; i++) {
                 if (include[i]) {
                     const targetType = getTypeOfPropertyOrIndexSignatureOfType(types[i], propertyName);
-                    if (targetType && related(getDiscriminatingType(), targetType)) {
+                    if (targetType && someType(getDiscriminatingType(), t => !!related(t, targetType))) {
                         matched = true;
                     }
                     else {

From c994e9ff702dffd9d91c0e47a79630e884e08c03 Mon Sep 17 00:00:00 2001
From: Anders Hejlsberg <andersh@microsoft.com>
Date: Sat, 22 Jun 2024 14:05:25 +0200
Subject: [PATCH 2/3] Accept new baselines

---
 ...entCompatWithDiscriminatedUnion.errors.txt | 26 ++++++++++++-------
 1 file changed, 16 insertions(+), 10 deletions(-)

diff --git a/tests/baselines/reference/assignmentCompatWithDiscriminatedUnion.errors.txt b/tests/baselines/reference/assignmentCompatWithDiscriminatedUnion.errors.txt
index e815b2a2ccb24..5a09377844cf8 100644
--- a/tests/baselines/reference/assignmentCompatWithDiscriminatedUnion.errors.txt
+++ b/tests/baselines/reference/assignmentCompatWithDiscriminatedUnion.errors.txt
@@ -1,13 +1,16 @@
 assignmentCompatWithDiscriminatedUnion.ts(44,5): error TS2322: Type 'S' is not assignable to type 'T'.
-  Type 'S' is not assignable to type '{ a: 0; b: 4 | 1; } | { a: 1; b: 2 | 4; }'.
-    Type 'S' is not assignable to type '{ a: 1; b: 2 | 4; }'.
-      Types of property 'a' are incompatible.
-        Type '0 | 2' is not assignable to type '1'.
-          Type '0' is not assignable to type '1'.
+  Type 'S' is not assignable to type '{ a: 0; b: 4 | 1; }'.
+    Types of property 'a' are incompatible.
+      Type '0 | 2' is not assignable to type '0'.
+        Type '2' is not assignable to type '0'.
 assignmentCompatWithDiscriminatedUnion.ts(58,5): error TS2322: Type 'S' is not assignable to type 'T'.
   Type 'S' is not assignable to type '{ a: 0; b: 4 | 1; } | { a: 2; b: 4 | 3; c: string; }'.
     Property 'c' is missing in type 'S' but required in type '{ a: 2; b: 4 | 3; c: string; }'.
 assignmentCompatWithDiscriminatedUnion.ts(82,5): error TS2322: Type 'S' is not assignable to type 'T'.
+  Type 'S' is not assignable to type '{ a: N; b: N; c: 2; }'.
+    Types of property 'c' are incompatible.
+      Type 'N' is not assignable to type '2'.
+        Type '0' is not assignable to type '2'.
 
 
 ==== assignmentCompatWithDiscriminatedUnion.ts (3 errors) ====
@@ -57,11 +60,10 @@ assignmentCompatWithDiscriminatedUnion.ts(82,5): error TS2322: Type 'S' is not a
         t = s;
         ~
 !!! error TS2322: Type 'S' is not assignable to type 'T'.
-!!! error TS2322:   Type 'S' is not assignable to type '{ a: 0; b: 4 | 1; } | { a: 1; b: 2 | 4; }'.
-!!! error TS2322:     Type 'S' is not assignable to type '{ a: 1; b: 2 | 4; }'.
-!!! error TS2322:       Types of property 'a' are incompatible.
-!!! error TS2322:         Type '0 | 2' is not assignable to type '1'.
-!!! error TS2322:           Type '0' is not assignable to type '1'.
+!!! error TS2322:   Type 'S' is not assignable to type '{ a: 0; b: 4 | 1; }'.
+!!! error TS2322:     Types of property 'a' are incompatible.
+!!! error TS2322:       Type '0 | 2' is not assignable to type '0'.
+!!! error TS2322:         Type '2' is not assignable to type '0'.
     }
     
     // Unmatched non-discriminants
@@ -107,6 +109,10 @@ assignmentCompatWithDiscriminatedUnion.ts(82,5): error TS2322: Type 'S' is not a
         t = s;
         ~
 !!! error TS2322: Type 'S' is not assignable to type 'T'.
+!!! error TS2322:   Type 'S' is not assignable to type '{ a: N; b: N; c: 2; }'.
+!!! error TS2322:     Types of property 'c' are incompatible.
+!!! error TS2322:       Type 'N' is not assignable to type '2'.
+!!! error TS2322:         Type '0' is not assignable to type '2'.
     }
     
     // https://github.com/Microsoft/TypeScript/issues/14865

From 559d8e7fc25ef14c3c9f1cc82dc7ea176fda555b Mon Sep 17 00:00:00 2001
From: Anders Hejlsberg <andersh@microsoft.com>
Date: Sun, 23 Jun 2024 09:43:40 +0200
Subject: [PATCH 3/3] Add tests

---
 ...entCompatWithDiscriminatedUnion.errors.txt |  24 ++++
 .../assignmentCompatWithDiscriminatedUnion.js |  41 ++++++
 ...gnmentCompatWithDiscriminatedUnion.symbols |  80 +++++++++++
 ...signmentCompatWithDiscriminatedUnion.types | 126 ++++++++++++++++++
 .../assignmentCompatWithDiscriminatedUnion.ts |  24 ++++
 5 files changed, 295 insertions(+)

diff --git a/tests/baselines/reference/assignmentCompatWithDiscriminatedUnion.errors.txt b/tests/baselines/reference/assignmentCompatWithDiscriminatedUnion.errors.txt
index 5a09377844cf8..91f79a95e46a5 100644
--- a/tests/baselines/reference/assignmentCompatWithDiscriminatedUnion.errors.txt
+++ b/tests/baselines/reference/assignmentCompatWithDiscriminatedUnion.errors.txt
@@ -232,4 +232,28 @@ assignmentCompatWithDiscriminatedUnion.ts(82,5): error TS2322: Type 'S' is not a
         declare const b: B;
         const a: A = b === "a" || b === "b" ? [b, 1] : ["c", ""];
     }
+    
+    // https://github.com/microsoft/TypeScript/issues/58603
+    namespace GH58603 {
+        enum MyEnum { A = 1, B = 2 }
+    
+        type TypeA = { kind: MyEnum.A, id?: number };
+        
+        type TypeB = { kind: MyEnum.B } & ({ id?: undefined } | { id: number });
+        
+        type MyType = TypeA | TypeB;
+        
+        function something(a: MyType): void {}
+        
+        function indirect(kind: MyEnum, id?: number): void {
+            something({ kind, id });
+        }
+        
+        type Foo = { kind: "a" | "b", value: number } | { kind: "a", value: undefined } | { kind: "b", value: undefined };
+        
+        function test(obj: { kind: "a" | "b", value: number | undefined }) {
+            let x1: Foo = obj;
+            let x2: Foo = { kind: obj.kind, value: obj.value };
+        }
+    }
     
\ No newline at end of file
diff --git a/tests/baselines/reference/assignmentCompatWithDiscriminatedUnion.js b/tests/baselines/reference/assignmentCompatWithDiscriminatedUnion.js
index 5a2635075402a..97fb4a9d2b1a6 100644
--- a/tests/baselines/reference/assignmentCompatWithDiscriminatedUnion.js
+++ b/tests/baselines/reference/assignmentCompatWithDiscriminatedUnion.js
@@ -202,6 +202,30 @@ namespace GH39357 {
     declare const b: B;
     const a: A = b === "a" || b === "b" ? [b, 1] : ["c", ""];
 }
+
+// https://github.com/microsoft/TypeScript/issues/58603
+namespace GH58603 {
+    enum MyEnum { A = 1, B = 2 }
+
+    type TypeA = { kind: MyEnum.A, id?: number };
+    
+    type TypeB = { kind: MyEnum.B } & ({ id?: undefined } | { id: number });
+    
+    type MyType = TypeA | TypeB;
+    
+    function something(a: MyType): void {}
+    
+    function indirect(kind: MyEnum, id?: number): void {
+        something({ kind, id });
+    }
+    
+    type Foo = { kind: "a" | "b", value: number } | { kind: "a", value: undefined } | { kind: "b", value: undefined };
+    
+    function test(obj: { kind: "a" | "b", value: number | undefined }) {
+        let x1: Foo = obj;
+        let x2: Foo = { kind: obj.kind, value: obj.value };
+    }
+}
 
 
 //// [assignmentCompatWithDiscriminatedUnion.js]
@@ -305,3 +329,20 @@ var GH39357;
 (function (GH39357) {
     var a = b === "a" || b === "b" ? [b, 1] : ["c", ""];
 })(GH39357 || (GH39357 = {}));
+// https://github.com/microsoft/TypeScript/issues/58603
+var GH58603;
+(function (GH58603) {
+    var MyEnum;
+    (function (MyEnum) {
+        MyEnum[MyEnum["A"] = 1] = "A";
+        MyEnum[MyEnum["B"] = 2] = "B";
+    })(MyEnum || (MyEnum = {}));
+    function something(a) { }
+    function indirect(kind, id) {
+        something({ kind: kind, id: id });
+    }
+    function test(obj) {
+        var x1 = obj;
+        var x2 = { kind: obj.kind, value: obj.value };
+    }
+})(GH58603 || (GH58603 = {}));
diff --git a/tests/baselines/reference/assignmentCompatWithDiscriminatedUnion.symbols b/tests/baselines/reference/assignmentCompatWithDiscriminatedUnion.symbols
index 926f52af3e0d1..e52ea8f834394 100644
--- a/tests/baselines/reference/assignmentCompatWithDiscriminatedUnion.symbols
+++ b/tests/baselines/reference/assignmentCompatWithDiscriminatedUnion.symbols
@@ -517,3 +517,83 @@ namespace GH39357 {
 >b : Symbol(b, Decl(assignmentCompatWithDiscriminatedUnion.ts, 198, 17))
 }
 
+// https://github.com/microsoft/TypeScript/issues/58603
+namespace GH58603 {
+>GH58603 : Symbol(GH58603, Decl(assignmentCompatWithDiscriminatedUnion.ts, 200, 1))
+
+    enum MyEnum { A = 1, B = 2 }
+>MyEnum : Symbol(MyEnum, Decl(assignmentCompatWithDiscriminatedUnion.ts, 203, 19))
+>A : Symbol(MyEnum.A, Decl(assignmentCompatWithDiscriminatedUnion.ts, 204, 17))
+>B : Symbol(MyEnum.B, Decl(assignmentCompatWithDiscriminatedUnion.ts, 204, 24))
+
+    type TypeA = { kind: MyEnum.A, id?: number };
+>TypeA : Symbol(TypeA, Decl(assignmentCompatWithDiscriminatedUnion.ts, 204, 32))
+>kind : Symbol(kind, Decl(assignmentCompatWithDiscriminatedUnion.ts, 206, 18))
+>MyEnum : Symbol(MyEnum, Decl(assignmentCompatWithDiscriminatedUnion.ts, 203, 19))
+>A : Symbol(MyEnum.A, Decl(assignmentCompatWithDiscriminatedUnion.ts, 204, 17))
+>id : Symbol(id, Decl(assignmentCompatWithDiscriminatedUnion.ts, 206, 34))
+    
+    type TypeB = { kind: MyEnum.B } & ({ id?: undefined } | { id: number });
+>TypeB : Symbol(TypeB, Decl(assignmentCompatWithDiscriminatedUnion.ts, 206, 49))
+>kind : Symbol(kind, Decl(assignmentCompatWithDiscriminatedUnion.ts, 208, 18))
+>MyEnum : Symbol(MyEnum, Decl(assignmentCompatWithDiscriminatedUnion.ts, 203, 19))
+>B : Symbol(MyEnum.B, Decl(assignmentCompatWithDiscriminatedUnion.ts, 204, 24))
+>id : Symbol(id, Decl(assignmentCompatWithDiscriminatedUnion.ts, 208, 40))
+>id : Symbol(id, Decl(assignmentCompatWithDiscriminatedUnion.ts, 208, 61))
+    
+    type MyType = TypeA | TypeB;
+>MyType : Symbol(MyType, Decl(assignmentCompatWithDiscriminatedUnion.ts, 208, 76))
+>TypeA : Symbol(TypeA, Decl(assignmentCompatWithDiscriminatedUnion.ts, 204, 32))
+>TypeB : Symbol(TypeB, Decl(assignmentCompatWithDiscriminatedUnion.ts, 206, 49))
+    
+    function something(a: MyType): void {}
+>something : Symbol(something, Decl(assignmentCompatWithDiscriminatedUnion.ts, 210, 32))
+>a : Symbol(a, Decl(assignmentCompatWithDiscriminatedUnion.ts, 212, 23))
+>MyType : Symbol(MyType, Decl(assignmentCompatWithDiscriminatedUnion.ts, 208, 76))
+    
+    function indirect(kind: MyEnum, id?: number): void {
+>indirect : Symbol(indirect, Decl(assignmentCompatWithDiscriminatedUnion.ts, 212, 42))
+>kind : Symbol(kind, Decl(assignmentCompatWithDiscriminatedUnion.ts, 214, 22))
+>MyEnum : Symbol(MyEnum, Decl(assignmentCompatWithDiscriminatedUnion.ts, 203, 19))
+>id : Symbol(id, Decl(assignmentCompatWithDiscriminatedUnion.ts, 214, 35))
+
+        something({ kind, id });
+>something : Symbol(something, Decl(assignmentCompatWithDiscriminatedUnion.ts, 210, 32))
+>kind : Symbol(kind, Decl(assignmentCompatWithDiscriminatedUnion.ts, 215, 19))
+>id : Symbol(id, Decl(assignmentCompatWithDiscriminatedUnion.ts, 215, 25))
+    }
+    
+    type Foo = { kind: "a" | "b", value: number } | { kind: "a", value: undefined } | { kind: "b", value: undefined };
+>Foo : Symbol(Foo, Decl(assignmentCompatWithDiscriminatedUnion.ts, 216, 5))
+>kind : Symbol(kind, Decl(assignmentCompatWithDiscriminatedUnion.ts, 218, 16))
+>value : Symbol(value, Decl(assignmentCompatWithDiscriminatedUnion.ts, 218, 33))
+>kind : Symbol(kind, Decl(assignmentCompatWithDiscriminatedUnion.ts, 218, 53))
+>value : Symbol(value, Decl(assignmentCompatWithDiscriminatedUnion.ts, 218, 64))
+>kind : Symbol(kind, Decl(assignmentCompatWithDiscriminatedUnion.ts, 218, 87))
+>value : Symbol(value, Decl(assignmentCompatWithDiscriminatedUnion.ts, 218, 98))
+    
+    function test(obj: { kind: "a" | "b", value: number | undefined }) {
+>test : Symbol(test, Decl(assignmentCompatWithDiscriminatedUnion.ts, 218, 118))
+>obj : Symbol(obj, Decl(assignmentCompatWithDiscriminatedUnion.ts, 220, 18))
+>kind : Symbol(kind, Decl(assignmentCompatWithDiscriminatedUnion.ts, 220, 24))
+>value : Symbol(value, Decl(assignmentCompatWithDiscriminatedUnion.ts, 220, 41))
+
+        let x1: Foo = obj;
+>x1 : Symbol(x1, Decl(assignmentCompatWithDiscriminatedUnion.ts, 221, 11))
+>Foo : Symbol(Foo, Decl(assignmentCompatWithDiscriminatedUnion.ts, 216, 5))
+>obj : Symbol(obj, Decl(assignmentCompatWithDiscriminatedUnion.ts, 220, 18))
+
+        let x2: Foo = { kind: obj.kind, value: obj.value };
+>x2 : Symbol(x2, Decl(assignmentCompatWithDiscriminatedUnion.ts, 222, 11))
+>Foo : Symbol(Foo, Decl(assignmentCompatWithDiscriminatedUnion.ts, 216, 5))
+>kind : Symbol(kind, Decl(assignmentCompatWithDiscriminatedUnion.ts, 222, 23))
+>obj.kind : Symbol(kind, Decl(assignmentCompatWithDiscriminatedUnion.ts, 220, 24))
+>obj : Symbol(obj, Decl(assignmentCompatWithDiscriminatedUnion.ts, 220, 18))
+>kind : Symbol(kind, Decl(assignmentCompatWithDiscriminatedUnion.ts, 220, 24))
+>value : Symbol(value, Decl(assignmentCompatWithDiscriminatedUnion.ts, 222, 39))
+>obj.value : Symbol(value, Decl(assignmentCompatWithDiscriminatedUnion.ts, 220, 41))
+>obj : Symbol(obj, Decl(assignmentCompatWithDiscriminatedUnion.ts, 220, 18))
+>value : Symbol(value, Decl(assignmentCompatWithDiscriminatedUnion.ts, 220, 41))
+    }
+}
+
diff --git a/tests/baselines/reference/assignmentCompatWithDiscriminatedUnion.types b/tests/baselines/reference/assignmentCompatWithDiscriminatedUnion.types
index ae1f923e573f2..be6617683be64 100644
--- a/tests/baselines/reference/assignmentCompatWithDiscriminatedUnion.types
+++ b/tests/baselines/reference/assignmentCompatWithDiscriminatedUnion.types
@@ -723,3 +723,129 @@ namespace GH39357 {
 >   : ^^
 }
 
+// https://github.com/microsoft/TypeScript/issues/58603
+namespace GH58603 {
+>GH58603 : typeof GH58603
+>        : ^^^^^^^^^^^^^^
+
+    enum MyEnum { A = 1, B = 2 }
+>MyEnum : MyEnum
+>       : ^^^^^^
+>A : MyEnum.A
+>  : ^^^^^^^^
+>1 : 1
+>  : ^
+>B : MyEnum.B
+>  : ^^^^^^^^
+>2 : 2
+>  : ^
+
+    type TypeA = { kind: MyEnum.A, id?: number };
+>TypeA : TypeA
+>      : ^^^^^
+>kind : MyEnum.A
+>     : ^^^^^^^^
+>MyEnum : any
+>       : ^^^
+>id : number
+>   : ^^^^^^
+    
+    type TypeB = { kind: MyEnum.B } & ({ id?: undefined } | { id: number });
+>TypeB : TypeB
+>      : ^^^^^
+>kind : MyEnum.B
+>     : ^^^^^^^^
+>MyEnum : any
+>       : ^^^
+>id : undefined
+>   : ^^^^^^^^^
+>id : number
+>   : ^^^^^^
+    
+    type MyType = TypeA | TypeB;
+>MyType : MyType
+>       : ^^^^^^
+    
+    function something(a: MyType): void {}
+>something : (a: MyType) => void
+>          : ^ ^^      ^^^^^    
+>a : MyType
+>  : ^^^^^^
+    
+    function indirect(kind: MyEnum, id?: number): void {
+>indirect : (kind: MyEnum, id?: number) => void
+>         : ^    ^^      ^^  ^^^      ^^^^^    
+>kind : MyEnum
+>     : ^^^^^^
+>id : number
+>   : ^^^^^^
+
+        something({ kind, id });
+>something({ kind, id }) : void
+>                        : ^^^^
+>something : (a: MyType) => void
+>          : ^ ^^      ^^^^^    
+>{ kind, id } : { kind: MyEnum; id: number; }
+>             : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+>kind : MyEnum
+>     : ^^^^^^
+>id : number
+>   : ^^^^^^
+    }
+    
+    type Foo = { kind: "a" | "b", value: number } | { kind: "a", value: undefined } | { kind: "b", value: undefined };
+>Foo : Foo
+>    : ^^^
+>kind : "a" | "b"
+>     : ^^^^^^^^^
+>value : number
+>      : ^^^^^^
+>kind : "a"
+>     : ^^^
+>value : undefined
+>      : ^^^^^^^^^
+>kind : "b"
+>     : ^^^
+>value : undefined
+>      : ^^^^^^^^^
+    
+    function test(obj: { kind: "a" | "b", value: number | undefined }) {
+>test : (obj: { kind: "a" | "b"; value: number | undefined; }) => void
+>     : ^   ^^                                               ^^^^^^^^^
+>obj : { kind: "a" | "b"; value: number | undefined; }
+>    : ^^^^^^^^         ^^^^^^^^^                  ^^^
+>kind : "a" | "b"
+>     : ^^^^^^^^^
+>value : number
+>      : ^^^^^^
+
+        let x1: Foo = obj;
+>x1 : Foo
+>   : ^^^
+>obj : { kind: "a" | "b"; value: number | undefined; }
+>    : ^^^^^^^^         ^^^^^^^^^                  ^^^
+
+        let x2: Foo = { kind: obj.kind, value: obj.value };
+>x2 : Foo
+>   : ^^^
+>{ kind: obj.kind, value: obj.value } : { kind: "a" | "b"; value: number; }
+>                                     : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+>kind : "a" | "b"
+>     : ^^^^^^^^^
+>obj.kind : "a" | "b"
+>         : ^^^^^^^^^
+>obj : { kind: "a" | "b"; value: number | undefined; }
+>    : ^^^^^^^^         ^^^^^^^^^                  ^^^
+>kind : "a" | "b"
+>     : ^^^^^^^^^
+>value : number
+>      : ^^^^^^
+>obj.value : number
+>          : ^^^^^^
+>obj : { kind: "a" | "b"; value: number | undefined; }
+>    : ^^^^^^^^         ^^^^^^^^^                  ^^^
+>value : number
+>      : ^^^^^^
+    }
+}
+
diff --git a/tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithDiscriminatedUnion.ts b/tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithDiscriminatedUnion.ts
index bea0b5ef78ffb..a717a1c718d80 100644
--- a/tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithDiscriminatedUnion.ts
+++ b/tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithDiscriminatedUnion.ts
@@ -199,3 +199,27 @@ namespace GH39357 {
     declare const b: B;
     const a: A = b === "a" || b === "b" ? [b, 1] : ["c", ""];
 }
+
+// https://github.com/microsoft/TypeScript/issues/58603
+namespace GH58603 {
+    enum MyEnum { A = 1, B = 2 }
+
+    type TypeA = { kind: MyEnum.A, id?: number };
+    
+    type TypeB = { kind: MyEnum.B } & ({ id?: undefined } | { id: number });
+    
+    type MyType = TypeA | TypeB;
+    
+    function something(a: MyType): void {}
+    
+    function indirect(kind: MyEnum, id?: number): void {
+        something({ kind, id });
+    }
+    
+    type Foo = { kind: "a" | "b", value: number } | { kind: "a", value: undefined } | { kind: "b", value: undefined };
+    
+    function test(obj: { kind: "a" | "b", value: number | undefined }) {
+        let x1: Foo = obj;
+        let x2: Foo = { kind: obj.kind, value: obj.value };
+    }
+}
