From c3807802371a89998887740182ee4a348b400b30 Mon Sep 17 00:00:00 2001 From: Prathmesh Ravindra Salunkhe Date: Wed, 1 Oct 2025 12:58:40 +0530 Subject: [PATCH] Add test for discriminant property order-independence and update baselines --- .../discriminantOrderIndependence.js | 61 +++++++ .../discriminantOrderIndependence.symbols | 106 ++++++++++++ .../discriminantOrderIndependence.types | 162 ++++++++++++++++++ .../compiler/discriminantOrderIndependence.ts | 41 +++++ 4 files changed, 370 insertions(+) create mode 100644 tests/baselines/reference/discriminantOrderIndependence.js create mode 100644 tests/baselines/reference/discriminantOrderIndependence.symbols create mode 100644 tests/baselines/reference/discriminantOrderIndependence.types create mode 100644 tests/cases/compiler/discriminantOrderIndependence.ts diff --git a/tests/baselines/reference/discriminantOrderIndependence.js b/tests/baselines/reference/discriminantOrderIndependence.js new file mode 100644 index 0000000000000..0dcd9850e352f --- /dev/null +++ b/tests/baselines/reference/discriminantOrderIndependence.js @@ -0,0 +1,61 @@ +//// [tests/cases/compiler/discriminantOrderIndependence.ts] //// + +//// [discriminantOrderIndependence.ts] +interface A { + subType: "b"; + type: "a"; +} + +declare let order1: + | { type: "1" } + | A + | { type: "2" } + | { type: "3" } + | undefined; + +// Should NOT error: 'order1' is possibly 'undefined' after the guard +if (order1 && order1.type === "a") { + order1.type; // Should be OK +} + +interface B { + subType: "b"; + type: "a"; +} + +declare let order2: + | { type: "1" } + | { type: "2" } + | { type: "3" } + | B + | undefined; + +// Should NOT error: 'order2' is possibly 'undefined' after the guard +if (order2 && order2.type === "a") { + order2.type; // Should be OK +} + +// Also test with !. type assertion +if (order1 && order1.type === "a") { + order1.type; // Should be OK +} +if (order2 && order2.type === "a") { + order2.type; // Should be OK +} + +//// [discriminantOrderIndependence.js] +// Should NOT error: 'order1' is possibly 'undefined' after the guard +if (order1 && order1.type === "a") { + order1.type; // Should be OK +} +// Should NOT error: 'order2' is possibly 'undefined' after the guard +if (order2 && order2.type === "a") { + order2.type; // Should be OK +} +// Also test with !. type assertion +if (order1 && order1.type === "a") { + order1.type; // Should be OK +} +if (order2 && order2.type === "a") { + order2.type; // Should be OK +} diff --git a/tests/baselines/reference/discriminantOrderIndependence.symbols b/tests/baselines/reference/discriminantOrderIndependence.symbols new file mode 100644 index 0000000000000..e470f892e5268 --- /dev/null +++ b/tests/baselines/reference/discriminantOrderIndependence.symbols @@ -0,0 +1,106 @@ +//// [tests/cases/compiler/discriminantOrderIndependence.ts] //// + +=== discriminantOrderIndependence.ts === +interface A { +>A : Symbol(A, Decl(discriminantOrderIndependence.ts, 0, 0)) + + subType: "b"; +>subType : Symbol(A.subType, Decl(discriminantOrderIndependence.ts, 0, 13)) + + type: "a"; +>type : Symbol(A.type, Decl(discriminantOrderIndependence.ts, 1, 17)) +} + +declare let order1: +>order1 : Symbol(order1, Decl(discriminantOrderIndependence.ts, 5, 11)) + + | { type: "1" } +>type : Symbol(type, Decl(discriminantOrderIndependence.ts, 6, 7)) + + | A +>A : Symbol(A, Decl(discriminantOrderIndependence.ts, 0, 0)) + + | { type: "2" } +>type : Symbol(type, Decl(discriminantOrderIndependence.ts, 8, 7)) + + | { type: "3" } +>type : Symbol(type, Decl(discriminantOrderIndependence.ts, 9, 7)) + + | undefined; + +// Should NOT error: 'order1' is possibly 'undefined' after the guard +if (order1 && order1.type === "a") { +>order1 : Symbol(order1, Decl(discriminantOrderIndependence.ts, 5, 11)) +>order1.type : Symbol(type, Decl(discriminantOrderIndependence.ts, 1, 17), Decl(discriminantOrderIndependence.ts, 6, 7), Decl(discriminantOrderIndependence.ts, 8, 7), Decl(discriminantOrderIndependence.ts, 9, 7)) +>order1 : Symbol(order1, Decl(discriminantOrderIndependence.ts, 5, 11)) +>type : Symbol(type, Decl(discriminantOrderIndependence.ts, 1, 17), Decl(discriminantOrderIndependence.ts, 6, 7), Decl(discriminantOrderIndependence.ts, 8, 7), Decl(discriminantOrderIndependence.ts, 9, 7)) + + order1.type; // Should be OK +>order1.type : Symbol(A.type, Decl(discriminantOrderIndependence.ts, 1, 17)) +>order1 : Symbol(order1, Decl(discriminantOrderIndependence.ts, 5, 11)) +>type : Symbol(A.type, Decl(discriminantOrderIndependence.ts, 1, 17)) +} + +interface B { +>B : Symbol(B, Decl(discriminantOrderIndependence.ts, 15, 1)) + + subType: "b"; +>subType : Symbol(B.subType, Decl(discriminantOrderIndependence.ts, 17, 13)) + + type: "a"; +>type : Symbol(B.type, Decl(discriminantOrderIndependence.ts, 18, 17)) +} + +declare let order2: +>order2 : Symbol(order2, Decl(discriminantOrderIndependence.ts, 22, 11)) + + | { type: "1" } +>type : Symbol(type, Decl(discriminantOrderIndependence.ts, 23, 7)) + + | { type: "2" } +>type : Symbol(type, Decl(discriminantOrderIndependence.ts, 24, 7)) + + | { type: "3" } +>type : Symbol(type, Decl(discriminantOrderIndependence.ts, 25, 7)) + + | B +>B : Symbol(B, Decl(discriminantOrderIndependence.ts, 15, 1)) + + | undefined; + +// Should NOT error: 'order2' is possibly 'undefined' after the guard +if (order2 && order2.type === "a") { +>order2 : Symbol(order2, Decl(discriminantOrderIndependence.ts, 22, 11)) +>order2.type : Symbol(type, Decl(discriminantOrderIndependence.ts, 18, 17), Decl(discriminantOrderIndependence.ts, 23, 7), Decl(discriminantOrderIndependence.ts, 24, 7), Decl(discriminantOrderIndependence.ts, 25, 7)) +>order2 : Symbol(order2, Decl(discriminantOrderIndependence.ts, 22, 11)) +>type : Symbol(type, Decl(discriminantOrderIndependence.ts, 18, 17), Decl(discriminantOrderIndependence.ts, 23, 7), Decl(discriminantOrderIndependence.ts, 24, 7), Decl(discriminantOrderIndependence.ts, 25, 7)) + + order2.type; // Should be OK +>order2.type : Symbol(B.type, Decl(discriminantOrderIndependence.ts, 18, 17)) +>order2 : Symbol(order2, Decl(discriminantOrderIndependence.ts, 22, 11)) +>type : Symbol(B.type, Decl(discriminantOrderIndependence.ts, 18, 17)) +} + +// Also test with !. type assertion +if (order1 && order1.type === "a") { +>order1 : Symbol(order1, Decl(discriminantOrderIndependence.ts, 5, 11)) +>order1.type : Symbol(type, Decl(discriminantOrderIndependence.ts, 1, 17), Decl(discriminantOrderIndependence.ts, 6, 7), Decl(discriminantOrderIndependence.ts, 8, 7), Decl(discriminantOrderIndependence.ts, 9, 7)) +>order1 : Symbol(order1, Decl(discriminantOrderIndependence.ts, 5, 11)) +>type : Symbol(type, Decl(discriminantOrderIndependence.ts, 1, 17), Decl(discriminantOrderIndependence.ts, 6, 7), Decl(discriminantOrderIndependence.ts, 8, 7), Decl(discriminantOrderIndependence.ts, 9, 7)) + + order1.type; // Should be OK +>order1.type : Symbol(A.type, Decl(discriminantOrderIndependence.ts, 1, 17)) +>order1 : Symbol(order1, Decl(discriminantOrderIndependence.ts, 5, 11)) +>type : Symbol(A.type, Decl(discriminantOrderIndependence.ts, 1, 17)) +} +if (order2 && order2.type === "a") { +>order2 : Symbol(order2, Decl(discriminantOrderIndependence.ts, 22, 11)) +>order2.type : Symbol(type, Decl(discriminantOrderIndependence.ts, 18, 17), Decl(discriminantOrderIndependence.ts, 23, 7), Decl(discriminantOrderIndependence.ts, 24, 7), Decl(discriminantOrderIndependence.ts, 25, 7)) +>order2 : Symbol(order2, Decl(discriminantOrderIndependence.ts, 22, 11)) +>type : Symbol(type, Decl(discriminantOrderIndependence.ts, 18, 17), Decl(discriminantOrderIndependence.ts, 23, 7), Decl(discriminantOrderIndependence.ts, 24, 7), Decl(discriminantOrderIndependence.ts, 25, 7)) + + order2.type; // Should be OK +>order2.type : Symbol(B.type, Decl(discriminantOrderIndependence.ts, 18, 17)) +>order2 : Symbol(order2, Decl(discriminantOrderIndependence.ts, 22, 11)) +>type : Symbol(B.type, Decl(discriminantOrderIndependence.ts, 18, 17)) +} diff --git a/tests/baselines/reference/discriminantOrderIndependence.types b/tests/baselines/reference/discriminantOrderIndependence.types new file mode 100644 index 0000000000000..d561f4cbefc21 --- /dev/null +++ b/tests/baselines/reference/discriminantOrderIndependence.types @@ -0,0 +1,162 @@ +//// [tests/cases/compiler/discriminantOrderIndependence.ts] //// + +=== discriminantOrderIndependence.ts === +interface A { + subType: "b"; +>subType : "b" +> : ^^^ + + type: "a"; +>type : "a" +> : ^^^ +} + +declare let order1: +>order1 : A | { type: "1"; } | { type: "2"; } | { type: "3"; } +> : ^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^ + + | { type: "1" } +>type : "1" +> : ^^^ + + | A + | { type: "2" } +>type : "2" +> : ^^^ + + | { type: "3" } +>type : "3" +> : ^^^ + + | undefined; + +// Should NOT error: 'order1' is possibly 'undefined' after the guard +if (order1 && order1.type === "a") { +>order1 && order1.type === "a" : boolean +> : ^^^^^^^ +>order1 : A | { type: "1"; } | { type: "2"; } | { type: "3"; } +> : ^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^ +>order1.type === "a" : boolean +> : ^^^^^^^ +>order1.type : "a" | "1" | "2" | "3" +> : ^^^^^^^^^^^^^^^^^^^^^ +>order1 : A | { type: "1"; } | { type: "2"; } | { type: "3"; } +> : ^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^ +>type : "a" | "1" | "2" | "3" +> : ^^^^^^^^^^^^^^^^^^^^^ +>"a" : "a" +> : ^^^ + + order1.type; // Should be OK +>order1.type : "a" +> : ^^^ +>order1 : A +> : ^ +>type : "a" +> : ^^^ +} + +interface B { + subType: "b"; +>subType : "b" +> : ^^^ + + type: "a"; +>type : "a" +> : ^^^ +} + +declare let order2: +>order2 : B | { type: "1"; } | { type: "2"; } | { type: "3"; } +> : ^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^ + + | { type: "1" } +>type : "1" +> : ^^^ + + | { type: "2" } +>type : "2" +> : ^^^ + + | { type: "3" } +>type : "3" +> : ^^^ + + | B + | undefined; + +// Should NOT error: 'order2' is possibly 'undefined' after the guard +if (order2 && order2.type === "a") { +>order2 && order2.type === "a" : boolean +> : ^^^^^^^ +>order2 : B | { type: "1"; } | { type: "2"; } | { type: "3"; } +> : ^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^ +>order2.type === "a" : boolean +> : ^^^^^^^ +>order2.type : "a" | "1" | "2" | "3" +> : ^^^^^^^^^^^^^^^^^^^^^ +>order2 : B | { type: "1"; } | { type: "2"; } | { type: "3"; } +> : ^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^ +>type : "a" | "1" | "2" | "3" +> : ^^^^^^^^^^^^^^^^^^^^^ +>"a" : "a" +> : ^^^ + + order2.type; // Should be OK +>order2.type : "a" +> : ^^^ +>order2 : B +> : ^ +>type : "a" +> : ^^^ +} + +// Also test with !. type assertion +if (order1 && order1.type === "a") { +>order1 && order1.type === "a" : boolean +> : ^^^^^^^ +>order1 : A | { type: "1"; } | { type: "2"; } | { type: "3"; } +> : ^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^ +>order1.type === "a" : boolean +> : ^^^^^^^ +>order1.type : "a" | "1" | "2" | "3" +> : ^^^^^^^^^^^^^^^^^^^^^ +>order1 : A | { type: "1"; } | { type: "2"; } | { type: "3"; } +> : ^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^ +>type : "a" | "1" | "2" | "3" +> : ^^^^^^^^^^^^^^^^^^^^^ +>"a" : "a" +> : ^^^ + + order1.type; // Should be OK +>order1.type : "a" +> : ^^^ +>order1 : A +> : ^ +>type : "a" +> : ^^^ +} +if (order2 && order2.type === "a") { +>order2 && order2.type === "a" : boolean +> : ^^^^^^^ +>order2 : B | { type: "1"; } | { type: "2"; } | { type: "3"; } +> : ^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^ +>order2.type === "a" : boolean +> : ^^^^^^^ +>order2.type : "a" | "1" | "2" | "3" +> : ^^^^^^^^^^^^^^^^^^^^^ +>order2 : B | { type: "1"; } | { type: "2"; } | { type: "3"; } +> : ^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^ +>type : "a" | "1" | "2" | "3" +> : ^^^^^^^^^^^^^^^^^^^^^ +>"a" : "a" +> : ^^^ + + order2.type; // Should be OK +>order2.type : "a" +> : ^^^ +>order2 : B +> : ^ +>type : "a" +> : ^^^ +} diff --git a/tests/cases/compiler/discriminantOrderIndependence.ts b/tests/cases/compiler/discriminantOrderIndependence.ts new file mode 100644 index 0000000000000..f43924efdf0b8 --- /dev/null +++ b/tests/cases/compiler/discriminantOrderIndependence.ts @@ -0,0 +1,41 @@ +interface A { + subType: "b"; + type: "a"; +} + +declare let order1: + | { type: "1" } + | A + | { type: "2" } + | { type: "3" } + | undefined; + +// Should NOT error: 'order1' is possibly 'undefined' after the guard +if (order1 && order1.type === "a") { + order1.type; // Should be OK +} + +interface B { + subType: "b"; + type: "a"; +} + +declare let order2: + | { type: "1" } + | { type: "2" } + | { type: "3" } + | B + | undefined; + +// Should NOT error: 'order2' is possibly 'undefined' after the guard +if (order2 && order2.type === "a") { + order2.type; // Should be OK +} + +// Also test with !. type assertion +if (order1 && order1.type === "a") { + order1.type; // Should be OK +} +if (order2 && order2.type === "a") { + order2.type; // Should be OK +} \ No newline at end of file