From dd07cdc60eef30442dc455001488578a968474dd Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 7 Oct 2021 16:36:34 -0700 Subject: [PATCH] Add tests --- .../dependentDestructuredVariables.js | 336 +++++++++++++ .../dependentDestructuredVariables.symbols | 409 ++++++++++++++++ .../dependentDestructuredVariables.types | 441 ++++++++++++++++++ .../dependentDestructuredVariables.ts | 161 +++++++ 4 files changed, 1347 insertions(+) create mode 100644 tests/baselines/reference/dependentDestructuredVariables.js create mode 100644 tests/baselines/reference/dependentDestructuredVariables.symbols create mode 100644 tests/baselines/reference/dependentDestructuredVariables.types create mode 100644 tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts diff --git a/tests/baselines/reference/dependentDestructuredVariables.js b/tests/baselines/reference/dependentDestructuredVariables.js new file mode 100644 index 0000000000000..82d41eb8b8d8d --- /dev/null +++ b/tests/baselines/reference/dependentDestructuredVariables.js @@ -0,0 +1,336 @@ +//// [dependentDestructuredVariables.ts] +type Action = + | { kind: 'A', payload: number } + | { kind: 'B', payload: string }; + +function f10({ kind, payload }: Action) { + if (kind === 'A') { + payload.toFixed(); + } + if (kind === 'B') { + payload.toUpperCase(); + } +} + +function f11(action: Action) { + const { kind, payload } = action; + if (kind === 'A') { + payload.toFixed(); + } + if (kind === 'B') { + payload.toUpperCase(); + } +} + +function f12({ kind, payload }: Action) { + switch (kind) { + case 'A': + payload.toFixed(); + break; + case 'B': + payload.toUpperCase(); + break; + default: + payload; // never + } +} + +type Action2 = + | { kind: 'A', payload: number | undefined } + | { kind: 'B', payload: string | undefined }; + +function f20({ kind, payload }: Action2) { + if (payload) { + if (kind === 'A') { + payload.toFixed(); + } + if (kind === 'B') { + payload.toUpperCase(); + } + } +} + +function f21(action: Action2) { + const { kind, payload } = action; + if (payload) { + if (kind === 'A') { + payload.toFixed(); + } + if (kind === 'B') { + payload.toUpperCase(); + } + } +} + +function f22(action: Action2) { + if (action.payload) { + const { kind, payload } = action; + if (kind === 'A') { + payload.toFixed(); + } + if (kind === 'B') { + payload.toUpperCase(); + } + } +} + +function f23({ kind, payload }: Action2) { + if (payload) { + switch (kind) { + case 'A': + payload.toFixed(); + break; + case 'B': + payload.toUpperCase(); + break; + default: + payload; // never + } + } +} + +type Foo = + | { kind: 'A', isA: true } + | { kind: 'B', isA: false } + | { kind: 'C', isA: false }; + +function f30({ kind, isA }: Foo) { + if (kind === 'A') { + isA; // true + } + if (kind === 'B') { + isA; // false + } + if (kind === 'C') { + isA; // false + } + if (isA) { + kind; // 'A' + } + else { + kind; // 'B' | 'C' + } +} + +// Repro from #35283 + +interface A { variant: 'a', value: T } + +interface B { variant: 'b', value: Array } + +type AB = A | B; + +declare function printValue(t: T): void; + +declare function printValueList(t: Array): void; + +function unrefined1(ab: AB): void { + const { variant, value } = ab; + if (variant === 'a') { + printValue(value); + } + else { + printValueList(value); + } +} + +// Repro from #38020 + +type Action3 = + | {type: 'add', payload: { toAdd: number } } + | {type: 'remove', payload: { toRemove: number } }; + +const reducerBroken = (state: number, { type, payload }: Action3) => { + switch (type) { + case 'add': + return state + payload.toAdd; + case 'remove': + return state - payload.toRemove; + } +} + +// Repro from #46143 + +declare var it: Iterator; +const { value, done } = it.next(); +if (!done) { + value; // number +} + + +//// [dependentDestructuredVariables.js] +"use strict"; +function f10({ kind, payload }) { + if (kind === 'A') { + payload.toFixed(); + } + if (kind === 'B') { + payload.toUpperCase(); + } +} +function f11(action) { + const { kind, payload } = action; + if (kind === 'A') { + payload.toFixed(); + } + if (kind === 'B') { + payload.toUpperCase(); + } +} +function f12({ kind, payload }) { + switch (kind) { + case 'A': + payload.toFixed(); + break; + case 'B': + payload.toUpperCase(); + break; + default: + payload; // never + } +} +function f20({ kind, payload }) { + if (payload) { + if (kind === 'A') { + payload.toFixed(); + } + if (kind === 'B') { + payload.toUpperCase(); + } + } +} +function f21(action) { + const { kind, payload } = action; + if (payload) { + if (kind === 'A') { + payload.toFixed(); + } + if (kind === 'B') { + payload.toUpperCase(); + } + } +} +function f22(action) { + if (action.payload) { + const { kind, payload } = action; + if (kind === 'A') { + payload.toFixed(); + } + if (kind === 'B') { + payload.toUpperCase(); + } + } +} +function f23({ kind, payload }) { + if (payload) { + switch (kind) { + case 'A': + payload.toFixed(); + break; + case 'B': + payload.toUpperCase(); + break; + default: + payload; // never + } + } +} +function f30({ kind, isA }) { + if (kind === 'A') { + isA; // true + } + if (kind === 'B') { + isA; // false + } + if (kind === 'C') { + isA; // false + } + if (isA) { + kind; // 'A' + } + else { + kind; // 'B' | 'C' + } +} +function unrefined1(ab) { + const { variant, value } = ab; + if (variant === 'a') { + printValue(value); + } + else { + printValueList(value); + } +} +const reducerBroken = (state, { type, payload }) => { + switch (type) { + case 'add': + return state + payload.toAdd; + case 'remove': + return state - payload.toRemove; + } +}; +const { value, done } = it.next(); +if (!done) { + value; // number +} + + +//// [dependentDestructuredVariables.d.ts] +declare type Action = { + kind: 'A'; + payload: number; +} | { + kind: 'B'; + payload: string; +}; +declare function f10({ kind, payload }: Action): void; +declare function f11(action: Action): void; +declare function f12({ kind, payload }: Action): void; +declare type Action2 = { + kind: 'A'; + payload: number | undefined; +} | { + kind: 'B'; + payload: string | undefined; +}; +declare function f20({ kind, payload }: Action2): void; +declare function f21(action: Action2): void; +declare function f22(action: Action2): void; +declare function f23({ kind, payload }: Action2): void; +declare type Foo = { + kind: 'A'; + isA: true; +} | { + kind: 'B'; + isA: false; +} | { + kind: 'C'; + isA: false; +}; +declare function f30({ kind, isA }: Foo): void; +interface A { + variant: 'a'; + value: T; +} +interface B { + variant: 'b'; + value: Array; +} +declare type AB = A | B; +declare function printValue(t: T): void; +declare function printValueList(t: Array): void; +declare function unrefined1(ab: AB): void; +declare type Action3 = { + type: 'add'; + payload: { + toAdd: number; + }; +} | { + type: 'remove'; + payload: { + toRemove: number; + }; +}; +declare const reducerBroken: (state: number, { type, payload }: Action3) => number; +declare var it: Iterator; +declare const value: any, done: boolean | undefined; diff --git a/tests/baselines/reference/dependentDestructuredVariables.symbols b/tests/baselines/reference/dependentDestructuredVariables.symbols new file mode 100644 index 0000000000000..2700f368585fe --- /dev/null +++ b/tests/baselines/reference/dependentDestructuredVariables.symbols @@ -0,0 +1,409 @@ +=== tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts === +type Action = +>Action : Symbol(Action, Decl(dependentDestructuredVariables.ts, 0, 0)) + + | { kind: 'A', payload: number } +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 1, 7)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 1, 18)) + + | { kind: 'B', payload: string }; +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 2, 7)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 2, 18)) + +function f10({ kind, payload }: Action) { +>f10 : Symbol(f10, Decl(dependentDestructuredVariables.ts, 2, 37)) +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 4, 14)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 4, 20)) +>Action : Symbol(Action, Decl(dependentDestructuredVariables.ts, 0, 0)) + + if (kind === 'A') { +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 4, 14)) + + payload.toFixed(); +>payload.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 4, 20)) +>toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) + } + if (kind === 'B') { +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 4, 14)) + + payload.toUpperCase(); +>payload.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 4, 20)) +>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) + } +} + +function f11(action: Action) { +>f11 : Symbol(f11, Decl(dependentDestructuredVariables.ts, 11, 1)) +>action : Symbol(action, Decl(dependentDestructuredVariables.ts, 13, 13)) +>Action : Symbol(Action, Decl(dependentDestructuredVariables.ts, 0, 0)) + + const { kind, payload } = action; +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 14, 11)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 14, 17)) +>action : Symbol(action, Decl(dependentDestructuredVariables.ts, 13, 13)) + + if (kind === 'A') { +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 14, 11)) + + payload.toFixed(); +>payload.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 14, 17)) +>toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) + } + if (kind === 'B') { +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 14, 11)) + + payload.toUpperCase(); +>payload.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 14, 17)) +>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) + } +} + +function f12({ kind, payload }: Action) { +>f12 : Symbol(f12, Decl(dependentDestructuredVariables.ts, 21, 1)) +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 23, 14)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 23, 20)) +>Action : Symbol(Action, Decl(dependentDestructuredVariables.ts, 0, 0)) + + switch (kind) { +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 23, 14)) + + case 'A': + payload.toFixed(); +>payload.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 23, 20)) +>toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) + + break; + case 'B': + payload.toUpperCase(); +>payload.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 23, 20)) +>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) + + break; + default: + payload; // never +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 23, 20)) + } +} + +type Action2 = +>Action2 : Symbol(Action2, Decl(dependentDestructuredVariables.ts, 34, 1)) + + | { kind: 'A', payload: number | undefined } +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 37, 7)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 37, 18)) + + | { kind: 'B', payload: string | undefined }; +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 38, 7)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 38, 18)) + +function f20({ kind, payload }: Action2) { +>f20 : Symbol(f20, Decl(dependentDestructuredVariables.ts, 38, 49)) +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 40, 14)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 40, 20)) +>Action2 : Symbol(Action2, Decl(dependentDestructuredVariables.ts, 34, 1)) + + if (payload) { +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 40, 20)) + + if (kind === 'A') { +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 40, 14)) + + payload.toFixed(); +>payload.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 40, 20)) +>toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) + } + if (kind === 'B') { +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 40, 14)) + + payload.toUpperCase(); +>payload.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 40, 20)) +>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) + } + } +} + +function f21(action: Action2) { +>f21 : Symbol(f21, Decl(dependentDestructuredVariables.ts, 49, 1)) +>action : Symbol(action, Decl(dependentDestructuredVariables.ts, 51, 13)) +>Action2 : Symbol(Action2, Decl(dependentDestructuredVariables.ts, 34, 1)) + + const { kind, payload } = action; +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 52, 11)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 52, 17)) +>action : Symbol(action, Decl(dependentDestructuredVariables.ts, 51, 13)) + + if (payload) { +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 52, 17)) + + if (kind === 'A') { +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 52, 11)) + + payload.toFixed(); +>payload.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 52, 17)) +>toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) + } + if (kind === 'B') { +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 52, 11)) + + payload.toUpperCase(); +>payload.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 52, 17)) +>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) + } + } +} + +function f22(action: Action2) { +>f22 : Symbol(f22, Decl(dependentDestructuredVariables.ts, 61, 1)) +>action : Symbol(action, Decl(dependentDestructuredVariables.ts, 63, 13)) +>Action2 : Symbol(Action2, Decl(dependentDestructuredVariables.ts, 34, 1)) + + if (action.payload) { +>action.payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 37, 18), Decl(dependentDestructuredVariables.ts, 38, 18)) +>action : Symbol(action, Decl(dependentDestructuredVariables.ts, 63, 13)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 37, 18), Decl(dependentDestructuredVariables.ts, 38, 18)) + + const { kind, payload } = action; +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 65, 15)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 65, 21)) +>action : Symbol(action, Decl(dependentDestructuredVariables.ts, 63, 13)) + + if (kind === 'A') { +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 65, 15)) + + payload.toFixed(); +>payload.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 65, 21)) +>toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) + } + if (kind === 'B') { +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 65, 15)) + + payload.toUpperCase(); +>payload.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 65, 21)) +>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) + } + } +} + +function f23({ kind, payload }: Action2) { +>f23 : Symbol(f23, Decl(dependentDestructuredVariables.ts, 73, 1)) +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 75, 14)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 75, 20)) +>Action2 : Symbol(Action2, Decl(dependentDestructuredVariables.ts, 34, 1)) + + if (payload) { +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 75, 20)) + + switch (kind) { +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 75, 14)) + + case 'A': + payload.toFixed(); +>payload.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 75, 20)) +>toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) + + break; + case 'B': + payload.toUpperCase(); +>payload.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 75, 20)) +>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) + + break; + default: + payload; // never +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 75, 20)) + } + } +} + +type Foo = +>Foo : Symbol(Foo, Decl(dependentDestructuredVariables.ts, 88, 1)) + + | { kind: 'A', isA: true } +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 91, 7)) +>isA : Symbol(isA, Decl(dependentDestructuredVariables.ts, 91, 18)) + + | { kind: 'B', isA: false } +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 92, 7)) +>isA : Symbol(isA, Decl(dependentDestructuredVariables.ts, 92, 18)) + + | { kind: 'C', isA: false }; +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 93, 7)) +>isA : Symbol(isA, Decl(dependentDestructuredVariables.ts, 93, 18)) + +function f30({ kind, isA }: Foo) { +>f30 : Symbol(f30, Decl(dependentDestructuredVariables.ts, 93, 32)) +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 95, 14)) +>isA : Symbol(isA, Decl(dependentDestructuredVariables.ts, 95, 20)) +>Foo : Symbol(Foo, Decl(dependentDestructuredVariables.ts, 88, 1)) + + if (kind === 'A') { +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 95, 14)) + + isA; // true +>isA : Symbol(isA, Decl(dependentDestructuredVariables.ts, 95, 20)) + } + if (kind === 'B') { +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 95, 14)) + + isA; // false +>isA : Symbol(isA, Decl(dependentDestructuredVariables.ts, 95, 20)) + } + if (kind === 'C') { +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 95, 14)) + + isA; // false +>isA : Symbol(isA, Decl(dependentDestructuredVariables.ts, 95, 20)) + } + if (isA) { +>isA : Symbol(isA, Decl(dependentDestructuredVariables.ts, 95, 20)) + + kind; // 'A' +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 95, 14)) + } + else { + kind; // 'B' | 'C' +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 95, 14)) + } +} + +// Repro from #35283 + +interface A { variant: 'a', value: T } +>A : Symbol(A, Decl(dependentDestructuredVariables.ts, 111, 1)) +>T : Symbol(T, Decl(dependentDestructuredVariables.ts, 115, 12)) +>variant : Symbol(A.variant, Decl(dependentDestructuredVariables.ts, 115, 16)) +>value : Symbol(A.value, Decl(dependentDestructuredVariables.ts, 115, 30)) +>T : Symbol(T, Decl(dependentDestructuredVariables.ts, 115, 12)) + +interface B { variant: 'b', value: Array } +>B : Symbol(B, Decl(dependentDestructuredVariables.ts, 115, 41)) +>T : Symbol(T, Decl(dependentDestructuredVariables.ts, 117, 12)) +>variant : Symbol(B.variant, Decl(dependentDestructuredVariables.ts, 117, 16)) +>value : Symbol(B.value, Decl(dependentDestructuredVariables.ts, 117, 30)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) +>T : Symbol(T, Decl(dependentDestructuredVariables.ts, 117, 12)) + +type AB = A | B; +>AB : Symbol(AB, Decl(dependentDestructuredVariables.ts, 117, 48)) +>T : Symbol(T, Decl(dependentDestructuredVariables.ts, 119, 8)) +>A : Symbol(A, Decl(dependentDestructuredVariables.ts, 111, 1)) +>T : Symbol(T, Decl(dependentDestructuredVariables.ts, 119, 8)) +>B : Symbol(B, Decl(dependentDestructuredVariables.ts, 115, 41)) +>T : Symbol(T, Decl(dependentDestructuredVariables.ts, 119, 8)) + +declare function printValue(t: T): void; +>printValue : Symbol(printValue, Decl(dependentDestructuredVariables.ts, 119, 25)) +>T : Symbol(T, Decl(dependentDestructuredVariables.ts, 121, 28)) +>t : Symbol(t, Decl(dependentDestructuredVariables.ts, 121, 31)) +>T : Symbol(T, Decl(dependentDestructuredVariables.ts, 121, 28)) + +declare function printValueList(t: Array): void; +>printValueList : Symbol(printValueList, Decl(dependentDestructuredVariables.ts, 121, 43)) +>T : Symbol(T, Decl(dependentDestructuredVariables.ts, 123, 32)) +>t : Symbol(t, Decl(dependentDestructuredVariables.ts, 123, 35)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) +>T : Symbol(T, Decl(dependentDestructuredVariables.ts, 123, 32)) + +function unrefined1(ab: AB): void { +>unrefined1 : Symbol(unrefined1, Decl(dependentDestructuredVariables.ts, 123, 54)) +>T : Symbol(T, Decl(dependentDestructuredVariables.ts, 125, 20)) +>ab : Symbol(ab, Decl(dependentDestructuredVariables.ts, 125, 23)) +>AB : Symbol(AB, Decl(dependentDestructuredVariables.ts, 117, 48)) +>T : Symbol(T, Decl(dependentDestructuredVariables.ts, 125, 20)) + + const { variant, value } = ab; +>variant : Symbol(variant, Decl(dependentDestructuredVariables.ts, 126, 11)) +>value : Symbol(value, Decl(dependentDestructuredVariables.ts, 126, 20)) +>ab : Symbol(ab, Decl(dependentDestructuredVariables.ts, 125, 23)) + + if (variant === 'a') { +>variant : Symbol(variant, Decl(dependentDestructuredVariables.ts, 126, 11)) + + printValue(value); +>printValue : Symbol(printValue, Decl(dependentDestructuredVariables.ts, 119, 25)) +>T : Symbol(T, Decl(dependentDestructuredVariables.ts, 125, 20)) +>value : Symbol(value, Decl(dependentDestructuredVariables.ts, 126, 20)) + } + else { + printValueList(value); +>printValueList : Symbol(printValueList, Decl(dependentDestructuredVariables.ts, 121, 43)) +>T : Symbol(T, Decl(dependentDestructuredVariables.ts, 125, 20)) +>value : Symbol(value, Decl(dependentDestructuredVariables.ts, 126, 20)) + } +} + +// Repro from #38020 + +type Action3 = +>Action3 : Symbol(Action3, Decl(dependentDestructuredVariables.ts, 133, 1)) + + | {type: 'add', payload: { toAdd: number } } +>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 138, 7)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 138, 19)) +>toAdd : Symbol(toAdd, Decl(dependentDestructuredVariables.ts, 138, 30)) + + | {type: 'remove', payload: { toRemove: number } }; +>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 139, 7)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 139, 22)) +>toRemove : Symbol(toRemove, Decl(dependentDestructuredVariables.ts, 139, 33)) + +const reducerBroken = (state: number, { type, payload }: Action3) => { +>reducerBroken : Symbol(reducerBroken, Decl(dependentDestructuredVariables.ts, 141, 5)) +>state : Symbol(state, Decl(dependentDestructuredVariables.ts, 141, 23)) +>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 141, 39)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 141, 45)) +>Action3 : Symbol(Action3, Decl(dependentDestructuredVariables.ts, 133, 1)) + + switch (type) { +>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 141, 39)) + + case 'add': + return state + payload.toAdd; +>state : Symbol(state, Decl(dependentDestructuredVariables.ts, 141, 23)) +>payload.toAdd : Symbol(toAdd, Decl(dependentDestructuredVariables.ts, 138, 30)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 141, 45)) +>toAdd : Symbol(toAdd, Decl(dependentDestructuredVariables.ts, 138, 30)) + + case 'remove': + return state - payload.toRemove; +>state : Symbol(state, Decl(dependentDestructuredVariables.ts, 141, 23)) +>payload.toRemove : Symbol(toRemove, Decl(dependentDestructuredVariables.ts, 139, 33)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 141, 45)) +>toRemove : Symbol(toRemove, Decl(dependentDestructuredVariables.ts, 139, 33)) + } +} + +// Repro from #46143 + +declare var it: Iterator; +>it : Symbol(it, Decl(dependentDestructuredVariables.ts, 152, 11)) +>Iterator : Symbol(Iterator, Decl(lib.es2015.iterable.d.ts, --, --)) + +const { value, done } = it.next(); +>value : Symbol(value, Decl(dependentDestructuredVariables.ts, 153, 7)) +>done : Symbol(done, Decl(dependentDestructuredVariables.ts, 153, 14)) +>it.next : Symbol(Iterator.next, Decl(lib.es2015.iterable.d.ts, --, --)) +>it : Symbol(it, Decl(dependentDestructuredVariables.ts, 152, 11)) +>next : Symbol(Iterator.next, Decl(lib.es2015.iterable.d.ts, --, --)) + +if (!done) { +>done : Symbol(done, Decl(dependentDestructuredVariables.ts, 153, 14)) + + value; // number +>value : Symbol(value, Decl(dependentDestructuredVariables.ts, 153, 7)) +} + diff --git a/tests/baselines/reference/dependentDestructuredVariables.types b/tests/baselines/reference/dependentDestructuredVariables.types new file mode 100644 index 0000000000000..1c8df34341cef --- /dev/null +++ b/tests/baselines/reference/dependentDestructuredVariables.types @@ -0,0 +1,441 @@ +=== tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts === +type Action = +>Action : Action + + | { kind: 'A', payload: number } +>kind : "A" +>payload : number + + | { kind: 'B', payload: string }; +>kind : "B" +>payload : string + +function f10({ kind, payload }: Action) { +>f10 : ({ kind, payload }: Action) => void +>kind : "A" | "B" +>payload : string | number + + if (kind === 'A') { +>kind === 'A' : boolean +>kind : "A" | "B" +>'A' : "A" + + payload.toFixed(); +>payload.toFixed() : string +>payload.toFixed : (fractionDigits?: number | undefined) => string +>payload : number +>toFixed : (fractionDigits?: number | undefined) => string + } + if (kind === 'B') { +>kind === 'B' : boolean +>kind : "A" | "B" +>'B' : "B" + + payload.toUpperCase(); +>payload.toUpperCase() : string +>payload.toUpperCase : () => string +>payload : string +>toUpperCase : () => string + } +} + +function f11(action: Action) { +>f11 : (action: Action) => void +>action : Action + + const { kind, payload } = action; +>kind : "A" | "B" +>payload : string | number +>action : Action + + if (kind === 'A') { +>kind === 'A' : boolean +>kind : "A" | "B" +>'A' : "A" + + payload.toFixed(); +>payload.toFixed() : string +>payload.toFixed : (fractionDigits?: number | undefined) => string +>payload : number +>toFixed : (fractionDigits?: number | undefined) => string + } + if (kind === 'B') { +>kind === 'B' : boolean +>kind : "A" | "B" +>'B' : "B" + + payload.toUpperCase(); +>payload.toUpperCase() : string +>payload.toUpperCase : () => string +>payload : string +>toUpperCase : () => string + } +} + +function f12({ kind, payload }: Action) { +>f12 : ({ kind, payload }: Action) => void +>kind : "A" | "B" +>payload : string | number + + switch (kind) { +>kind : "A" | "B" + + case 'A': +>'A' : "A" + + payload.toFixed(); +>payload.toFixed() : string +>payload.toFixed : (fractionDigits?: number | undefined) => string +>payload : number +>toFixed : (fractionDigits?: number | undefined) => string + + break; + case 'B': +>'B' : "B" + + payload.toUpperCase(); +>payload.toUpperCase() : string +>payload.toUpperCase : () => string +>payload : string +>toUpperCase : () => string + + break; + default: + payload; // never +>payload : never + } +} + +type Action2 = +>Action2 : Action2 + + | { kind: 'A', payload: number | undefined } +>kind : "A" +>payload : number | undefined + + | { kind: 'B', payload: string | undefined }; +>kind : "B" +>payload : string | undefined + +function f20({ kind, payload }: Action2) { +>f20 : ({ kind, payload }: Action2) => void +>kind : "A" | "B" +>payload : string | number | undefined + + if (payload) { +>payload : string | number | undefined + + if (kind === 'A') { +>kind === 'A' : boolean +>kind : "A" | "B" +>'A' : "A" + + payload.toFixed(); +>payload.toFixed() : string +>payload.toFixed : (fractionDigits?: number | undefined) => string +>payload : number +>toFixed : (fractionDigits?: number | undefined) => string + } + if (kind === 'B') { +>kind === 'B' : boolean +>kind : "A" | "B" +>'B' : "B" + + payload.toUpperCase(); +>payload.toUpperCase() : string +>payload.toUpperCase : () => string +>payload : string +>toUpperCase : () => string + } + } +} + +function f21(action: Action2) { +>f21 : (action: Action2) => void +>action : Action2 + + const { kind, payload } = action; +>kind : "A" | "B" +>payload : string | number | undefined +>action : Action2 + + if (payload) { +>payload : string | number | undefined + + if (kind === 'A') { +>kind === 'A' : boolean +>kind : "A" | "B" +>'A' : "A" + + payload.toFixed(); +>payload.toFixed() : string +>payload.toFixed : (fractionDigits?: number | undefined) => string +>payload : number +>toFixed : (fractionDigits?: number | undefined) => string + } + if (kind === 'B') { +>kind === 'B' : boolean +>kind : "A" | "B" +>'B' : "B" + + payload.toUpperCase(); +>payload.toUpperCase() : string +>payload.toUpperCase : () => string +>payload : string +>toUpperCase : () => string + } + } +} + +function f22(action: Action2) { +>f22 : (action: Action2) => void +>action : Action2 + + if (action.payload) { +>action.payload : string | number | undefined +>action : Action2 +>payload : string | number | undefined + + const { kind, payload } = action; +>kind : "A" | "B" +>payload : string | number +>action : Action2 + + if (kind === 'A') { +>kind === 'A' : boolean +>kind : "A" | "B" +>'A' : "A" + + payload.toFixed(); +>payload.toFixed() : string +>payload.toFixed : (fractionDigits?: number | undefined) => string +>payload : number +>toFixed : (fractionDigits?: number | undefined) => string + } + if (kind === 'B') { +>kind === 'B' : boolean +>kind : "A" | "B" +>'B' : "B" + + payload.toUpperCase(); +>payload.toUpperCase() : string +>payload.toUpperCase : () => string +>payload : string +>toUpperCase : () => string + } + } +} + +function f23({ kind, payload }: Action2) { +>f23 : ({ kind, payload }: Action2) => void +>kind : "A" | "B" +>payload : string | number | undefined + + if (payload) { +>payload : string | number | undefined + + switch (kind) { +>kind : "A" | "B" + + case 'A': +>'A' : "A" + + payload.toFixed(); +>payload.toFixed() : string +>payload.toFixed : (fractionDigits?: number | undefined) => string +>payload : number +>toFixed : (fractionDigits?: number | undefined) => string + + break; + case 'B': +>'B' : "B" + + payload.toUpperCase(); +>payload.toUpperCase() : string +>payload.toUpperCase : () => string +>payload : string +>toUpperCase : () => string + + break; + default: + payload; // never +>payload : never + } + } +} + +type Foo = +>Foo : Foo + + | { kind: 'A', isA: true } +>kind : "A" +>isA : true +>true : true + + | { kind: 'B', isA: false } +>kind : "B" +>isA : false +>false : false + + | { kind: 'C', isA: false }; +>kind : "C" +>isA : false +>false : false + +function f30({ kind, isA }: Foo) { +>f30 : ({ kind, isA }: Foo) => void +>kind : "A" | "B" | "C" +>isA : boolean + + if (kind === 'A') { +>kind === 'A' : boolean +>kind : "A" | "B" | "C" +>'A' : "A" + + isA; // true +>isA : true + } + if (kind === 'B') { +>kind === 'B' : boolean +>kind : "A" | "B" | "C" +>'B' : "B" + + isA; // false +>isA : false + } + if (kind === 'C') { +>kind === 'C' : boolean +>kind : "A" | "B" | "C" +>'C' : "C" + + isA; // false +>isA : false + } + if (isA) { +>isA : boolean + + kind; // 'A' +>kind : "A" + } + else { + kind; // 'B' | 'C' +>kind : "B" | "C" + } +} + +// Repro from #35283 + +interface A { variant: 'a', value: T } +>variant : "a" +>value : T + +interface B { variant: 'b', value: Array } +>variant : "b" +>value : T[] + +type AB = A | B; +>AB : AB + +declare function printValue(t: T): void; +>printValue : (t: T) => void +>t : T + +declare function printValueList(t: Array): void; +>printValueList : (t: Array) => void +>t : T[] + +function unrefined1(ab: AB): void { +>unrefined1 : (ab: AB) => void +>ab : AB + + const { variant, value } = ab; +>variant : "a" | "b" +>value : T | T[] +>ab : AB + + if (variant === 'a') { +>variant === 'a' : boolean +>variant : "a" | "b" +>'a' : "a" + + printValue(value); +>printValue(value) : void +>printValue : (t: T) => void +>value : T + } + else { + printValueList(value); +>printValueList(value) : void +>printValueList : (t: T[]) => void +>value : T[] + } +} + +// Repro from #38020 + +type Action3 = +>Action3 : Action3 + + | {type: 'add', payload: { toAdd: number } } +>type : "add" +>payload : { toAdd: number; } +>toAdd : number + + | {type: 'remove', payload: { toRemove: number } }; +>type : "remove" +>payload : { toRemove: number; } +>toRemove : number + +const reducerBroken = (state: number, { type, payload }: Action3) => { +>reducerBroken : (state: number, { type, payload }: Action3) => number +>(state: number, { type, payload }: Action3) => { switch (type) { case 'add': return state + payload.toAdd; case 'remove': return state - payload.toRemove; }} : (state: number, { type, payload }: Action3) => number +>state : number +>type : "add" | "remove" +>payload : { toAdd: number; } | { toRemove: number; } + + switch (type) { +>type : "add" | "remove" + + case 'add': +>'add' : "add" + + return state + payload.toAdd; +>state + payload.toAdd : number +>state : number +>payload.toAdd : number +>payload : { toAdd: number; } +>toAdd : number + + case 'remove': +>'remove' : "remove" + + return state - payload.toRemove; +>state - payload.toRemove : number +>state : number +>payload.toRemove : number +>payload : { toRemove: number; } +>toRemove : number + } +} + +// Repro from #46143 + +declare var it: Iterator; +>it : Iterator + +const { value, done } = it.next(); +>value : any +>done : boolean | undefined +>it.next() : IteratorResult +>it.next : (...args: [] | [undefined]) => IteratorResult +>it : Iterator +>next : (...args: [] | [undefined]) => IteratorResult + +if (!done) { +>!done : boolean +>done : boolean | undefined + + value; // number +>value : number +} + diff --git a/tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts b/tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts new file mode 100644 index 0000000000000..55e95ddf09163 --- /dev/null +++ b/tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts @@ -0,0 +1,161 @@ +// @strict: true +// @declaration: true +// @target: es2015 + +type Action = + | { kind: 'A', payload: number } + | { kind: 'B', payload: string }; + +function f10({ kind, payload }: Action) { + if (kind === 'A') { + payload.toFixed(); + } + if (kind === 'B') { + payload.toUpperCase(); + } +} + +function f11(action: Action) { + const { kind, payload } = action; + if (kind === 'A') { + payload.toFixed(); + } + if (kind === 'B') { + payload.toUpperCase(); + } +} + +function f12({ kind, payload }: Action) { + switch (kind) { + case 'A': + payload.toFixed(); + break; + case 'B': + payload.toUpperCase(); + break; + default: + payload; // never + } +} + +type Action2 = + | { kind: 'A', payload: number | undefined } + | { kind: 'B', payload: string | undefined }; + +function f20({ kind, payload }: Action2) { + if (payload) { + if (kind === 'A') { + payload.toFixed(); + } + if (kind === 'B') { + payload.toUpperCase(); + } + } +} + +function f21(action: Action2) { + const { kind, payload } = action; + if (payload) { + if (kind === 'A') { + payload.toFixed(); + } + if (kind === 'B') { + payload.toUpperCase(); + } + } +} + +function f22(action: Action2) { + if (action.payload) { + const { kind, payload } = action; + if (kind === 'A') { + payload.toFixed(); + } + if (kind === 'B') { + payload.toUpperCase(); + } + } +} + +function f23({ kind, payload }: Action2) { + if (payload) { + switch (kind) { + case 'A': + payload.toFixed(); + break; + case 'B': + payload.toUpperCase(); + break; + default: + payload; // never + } + } +} + +type Foo = + | { kind: 'A', isA: true } + | { kind: 'B', isA: false } + | { kind: 'C', isA: false }; + +function f30({ kind, isA }: Foo) { + if (kind === 'A') { + isA; // true + } + if (kind === 'B') { + isA; // false + } + if (kind === 'C') { + isA; // false + } + if (isA) { + kind; // 'A' + } + else { + kind; // 'B' | 'C' + } +} + +// Repro from #35283 + +interface A { variant: 'a', value: T } + +interface B { variant: 'b', value: Array } + +type AB = A | B; + +declare function printValue(t: T): void; + +declare function printValueList(t: Array): void; + +function unrefined1(ab: AB): void { + const { variant, value } = ab; + if (variant === 'a') { + printValue(value); + } + else { + printValueList(value); + } +} + +// Repro from #38020 + +type Action3 = + | {type: 'add', payload: { toAdd: number } } + | {type: 'remove', payload: { toRemove: number } }; + +const reducerBroken = (state: number, { type, payload }: Action3) => { + switch (type) { + case 'add': + return state + payload.toAdd; + case 'remove': + return state - payload.toRemove; + } +} + +// Repro from #46143 + +declare var it: Iterator; +const { value, done } = it.next(); +if (!done) { + value; // number +}