diff --git a/tests/baselines/reference/controlFlowInstanceof.js b/tests/baselines/reference/controlFlowInstanceof.js index 7c7833927c..3f2287b462 100644 --- a/tests/baselines/reference/controlFlowInstanceof.js +++ b/tests/baselines/reference/controlFlowInstanceof.js @@ -77,6 +77,25 @@ function foo(x: A | undefined) { x; // A } x; // A +} + +// X is neither assignable to Y nor a subtype of Y +// Y is assignable to X, but not a subtype of X + +interface X { + x?: string; +} + +class Y { + y: string; +} + +function goo(x: X) { + x; + if (x instanceof Y) { + x.y; + } + x; } //// [controlFlowInstanceof.js] @@ -154,3 +173,12 @@ function foo(x) { } x; // A } +class Y { +} +function goo(x) { + x; + if (x instanceof Y) { + x.y; + } + x; +} diff --git a/tests/baselines/reference/controlFlowInstanceof.symbols b/tests/baselines/reference/controlFlowInstanceof.symbols index 64b567c154..3189482799 100644 --- a/tests/baselines/reference/controlFlowInstanceof.symbols +++ b/tests/baselines/reference/controlFlowInstanceof.symbols @@ -192,3 +192,41 @@ function foo(x: A | undefined) { x; // A >x : Symbol(x, Decl(controlFlowInstanceof.ts, 50, 13)) } + +// X is neither assignable to Y nor a subtype of Y +// Y is assignable to X, but not a subtype of X + +interface X { +>X : Symbol(X, Decl(controlFlowInstanceof.ts, 78, 1)) + + x?: string; +>x : Symbol(X.x, Decl(controlFlowInstanceof.ts, 83, 13)) +} + +class Y { +>Y : Symbol(Y, Decl(controlFlowInstanceof.ts, 85, 1)) + + y: string; +>y : Symbol(Y.y, Decl(controlFlowInstanceof.ts, 87, 9)) +} + +function goo(x: X) { +>goo : Symbol(goo, Decl(controlFlowInstanceof.ts, 89, 1)) +>x : Symbol(x, Decl(controlFlowInstanceof.ts, 91, 13)) +>X : Symbol(X, Decl(controlFlowInstanceof.ts, 78, 1)) + + x; +>x : Symbol(x, Decl(controlFlowInstanceof.ts, 91, 13)) + + if (x instanceof Y) { +>x : Symbol(x, Decl(controlFlowInstanceof.ts, 91, 13)) +>Y : Symbol(Y, Decl(controlFlowInstanceof.ts, 85, 1)) + + x.y; +>x.y : Symbol(Y.y, Decl(controlFlowInstanceof.ts, 87, 9)) +>x : Symbol(x, Decl(controlFlowInstanceof.ts, 91, 13)) +>y : Symbol(Y.y, Decl(controlFlowInstanceof.ts, 87, 9)) + } + x; +>x : Symbol(x, Decl(controlFlowInstanceof.ts, 91, 13)) +} diff --git a/tests/baselines/reference/controlFlowInstanceof.types b/tests/baselines/reference/controlFlowInstanceof.types index 362715914f..e52d1a25b1 100644 --- a/tests/baselines/reference/controlFlowInstanceof.types +++ b/tests/baselines/reference/controlFlowInstanceof.types @@ -215,3 +215,42 @@ function foo(x: A | undefined) { x; // A >x : A } + +// X is neither assignable to Y nor a subtype of Y +// Y is assignable to X, but not a subtype of X + +interface X { +>X : X + + x?: string; +>x : string +} + +class Y { +>Y : Y + + y: string; +>y : string +} + +function goo(x: X) { +>goo : (x: X) => void +>x : X +>X : X + + x; +>x : X + + if (x instanceof Y) { +>x instanceof Y : boolean +>x : X +>Y : typeof Y + + x.y; +>x.y : string +>x : Y +>y : string + } + x; +>x : X +} diff --git a/tests/baselines/reference/discriminantsAndTypePredicates.js b/tests/baselines/reference/discriminantsAndTypePredicates.js new file mode 100644 index 0000000000..66cfe056ab --- /dev/null +++ b/tests/baselines/reference/discriminantsAndTypePredicates.js @@ -0,0 +1,59 @@ +//// [discriminantsAndTypePredicates.ts] +// Repro from #10145 + +interface A { type: 'A' } +interface B { type: 'B' } + +function isA(x: A | B): x is A { return x.type === 'A'; } +function isB(x: A | B): x is B { return x.type === 'B'; } + +function foo1(x: A | B): any { + x; // A | B + if (isA(x)) { + return x; // A + } + x; // B + if (isB(x)) { + return x; // B + } + x; // never +} + +function foo2(x: A | B): any { + x; // A | B + if (x.type === 'A') { + return x; // A + } + x; // B + if (x.type === 'B') { + return x; // B + } + x; // never +} + +//// [discriminantsAndTypePredicates.js] +// Repro from #10145 +function isA(x) { return x.type === 'A'; } +function isB(x) { return x.type === 'B'; } +function foo1(x) { + x; // A | B + if (isA(x)) { + return x; // A + } + x; // B + if (isB(x)) { + return x; // B + } + x; // never +} +function foo2(x) { + x; // A | B + if (x.type === 'A') { + return x; // A + } + x; // B + if (x.type === 'B') { + return x; // B + } + x; // never +} diff --git a/tests/baselines/reference/discriminantsAndTypePredicates.symbols b/tests/baselines/reference/discriminantsAndTypePredicates.symbols new file mode 100644 index 0000000000..4f41282393 --- /dev/null +++ b/tests/baselines/reference/discriminantsAndTypePredicates.symbols @@ -0,0 +1,94 @@ +=== tests/cases/compiler/discriminantsAndTypePredicates.ts === +// Repro from #10145 + +interface A { type: 'A' } +>A : Symbol(A, Decl(discriminantsAndTypePredicates.ts, 0, 0)) +>type : Symbol(A.type, Decl(discriminantsAndTypePredicates.ts, 2, 13)) + +interface B { type: 'B' } +>B : Symbol(B, Decl(discriminantsAndTypePredicates.ts, 2, 25)) +>type : Symbol(B.type, Decl(discriminantsAndTypePredicates.ts, 3, 13)) + +function isA(x: A | B): x is A { return x.type === 'A'; } +>isA : Symbol(isA, Decl(discriminantsAndTypePredicates.ts, 3, 25)) +>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 5, 13)) +>A : Symbol(A, Decl(discriminantsAndTypePredicates.ts, 0, 0)) +>B : Symbol(B, Decl(discriminantsAndTypePredicates.ts, 2, 25)) +>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 5, 13)) +>A : Symbol(A, Decl(discriminantsAndTypePredicates.ts, 0, 0)) +>x.type : Symbol(type, Decl(discriminantsAndTypePredicates.ts, 2, 13), Decl(discriminantsAndTypePredicates.ts, 3, 13)) +>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 5, 13)) +>type : Symbol(type, Decl(discriminantsAndTypePredicates.ts, 2, 13), Decl(discriminantsAndTypePredicates.ts, 3, 13)) + +function isB(x: A | B): x is B { return x.type === 'B'; } +>isB : Symbol(isB, Decl(discriminantsAndTypePredicates.ts, 5, 57)) +>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 6, 13)) +>A : Symbol(A, Decl(discriminantsAndTypePredicates.ts, 0, 0)) +>B : Symbol(B, Decl(discriminantsAndTypePredicates.ts, 2, 25)) +>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 6, 13)) +>B : Symbol(B, Decl(discriminantsAndTypePredicates.ts, 2, 25)) +>x.type : Symbol(type, Decl(discriminantsAndTypePredicates.ts, 2, 13), Decl(discriminantsAndTypePredicates.ts, 3, 13)) +>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 6, 13)) +>type : Symbol(type, Decl(discriminantsAndTypePredicates.ts, 2, 13), Decl(discriminantsAndTypePredicates.ts, 3, 13)) + +function foo1(x: A | B): any { +>foo1 : Symbol(foo1, Decl(discriminantsAndTypePredicates.ts, 6, 57)) +>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 8, 14)) +>A : Symbol(A, Decl(discriminantsAndTypePredicates.ts, 0, 0)) +>B : Symbol(B, Decl(discriminantsAndTypePredicates.ts, 2, 25)) + + x; // A | B +>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 8, 14)) + + if (isA(x)) { +>isA : Symbol(isA, Decl(discriminantsAndTypePredicates.ts, 3, 25)) +>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 8, 14)) + + return x; // A +>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 8, 14)) + } + x; // B +>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 8, 14)) + + if (isB(x)) { +>isB : Symbol(isB, Decl(discriminantsAndTypePredicates.ts, 5, 57)) +>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 8, 14)) + + return x; // B +>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 8, 14)) + } + x; // never +>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 8, 14)) +} + +function foo2(x: A | B): any { +>foo2 : Symbol(foo2, Decl(discriminantsAndTypePredicates.ts, 18, 1)) +>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 20, 14)) +>A : Symbol(A, Decl(discriminantsAndTypePredicates.ts, 0, 0)) +>B : Symbol(B, Decl(discriminantsAndTypePredicates.ts, 2, 25)) + + x; // A | B +>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 20, 14)) + + if (x.type === 'A') { +>x.type : Symbol(type, Decl(discriminantsAndTypePredicates.ts, 2, 13), Decl(discriminantsAndTypePredicates.ts, 3, 13)) +>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 20, 14)) +>type : Symbol(type, Decl(discriminantsAndTypePredicates.ts, 2, 13), Decl(discriminantsAndTypePredicates.ts, 3, 13)) + + return x; // A +>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 20, 14)) + } + x; // B +>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 20, 14)) + + if (x.type === 'B') { +>x.type : Symbol(B.type, Decl(discriminantsAndTypePredicates.ts, 3, 13)) +>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 20, 14)) +>type : Symbol(B.type, Decl(discriminantsAndTypePredicates.ts, 3, 13)) + + return x; // B +>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 20, 14)) + } + x; // never +>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 20, 14)) +} diff --git a/tests/baselines/reference/discriminantsAndTypePredicates.types b/tests/baselines/reference/discriminantsAndTypePredicates.types new file mode 100644 index 0000000000..f7675b1475 --- /dev/null +++ b/tests/baselines/reference/discriminantsAndTypePredicates.types @@ -0,0 +1,104 @@ +=== tests/cases/compiler/discriminantsAndTypePredicates.ts === +// Repro from #10145 + +interface A { type: 'A' } +>A : A +>type : "A" + +interface B { type: 'B' } +>B : B +>type : "B" + +function isA(x: A | B): x is A { return x.type === 'A'; } +>isA : (x: A | B) => x is A +>x : A | B +>A : A +>B : B +>x : any +>A : A +>x.type === 'A' : boolean +>x.type : "A" | "B" +>x : A | B +>type : "A" | "B" +>'A' : "A" + +function isB(x: A | B): x is B { return x.type === 'B'; } +>isB : (x: A | B) => x is B +>x : A | B +>A : A +>B : B +>x : any +>B : B +>x.type === 'B' : boolean +>x.type : "A" | "B" +>x : A | B +>type : "A" | "B" +>'B' : "B" + +function foo1(x: A | B): any { +>foo1 : (x: A | B) => any +>x : A | B +>A : A +>B : B + + x; // A | B +>x : A | B + + if (isA(x)) { +>isA(x) : boolean +>isA : (x: A | B) => x is A +>x : A | B + + return x; // A +>x : A + } + x; // B +>x : B + + if (isB(x)) { +>isB(x) : boolean +>isB : (x: A | B) => x is B +>x : B + + return x; // B +>x : B + } + x; // never +>x : never +} + +function foo2(x: A | B): any { +>foo2 : (x: A | B) => any +>x : A | B +>A : A +>B : B + + x; // A | B +>x : A | B + + if (x.type === 'A') { +>x.type === 'A' : boolean +>x.type : "A" | "B" +>x : A | B +>type : "A" | "B" +>'A' : "A" + + return x; // A +>x : A + } + x; // B +>x : B + + if (x.type === 'B') { +>x.type === 'B' : boolean +>x.type : "B" +>x : B +>type : "B" +>'B' : "B" + + return x; // B +>x : B + } + x; // never +>x : never +}