• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// @strict: true
2
3type Item = Item1 | Item2;
4
5interface Base {
6    bar: boolean;
7}
8
9interface Item1 extends Base {
10    kind: "A";
11    foo: string | undefined;
12    baz: boolean;
13    qux: true;
14}
15
16interface Item2 extends Base {
17    kind: "B";
18    foo: string | undefined;
19    baz: boolean;
20    qux: false;
21}
22
23function goo1(x: Item) {
24    if (x.kind === "A" && x.foo !== undefined) {
25        x.foo.length;
26    }
27}
28
29function goo2(x: Item) {
30    if (x.foo !== undefined && x.kind === "A") {
31        x.foo.length;  // Error, intervening discriminant guard
32    }
33}
34
35function foo1(x: Item) {
36    if (x.bar && x.foo !== undefined) {
37        x.foo.length;
38    }
39}
40
41function foo2(x: Item) {
42    if (x.foo !== undefined && x.bar) {
43        x.foo.length;
44    }
45}
46
47function foo3(x: Item) {
48    if (x.baz && x.foo !== undefined) {
49        x.foo.length;
50    }
51}
52
53function foo4(x: Item) {
54    if (x.foo !== undefined && x.baz) {
55        x.foo.length;
56    }
57}
58
59function foo5(x: Item) {
60    if (x.qux && x.foo !== undefined) {
61        x.foo.length;
62    }
63}
64
65function foo6(x: Item) {
66    if (x.foo !== undefined && x.qux) {
67        x.foo.length;  // Error, intervening discriminant guard
68    }
69}
70
71// Repro from #27493
72
73enum Types { Str = 1, Num = 2 }
74
75type Instance = StrType | NumType;
76
77interface StrType {
78    type: Types.Str;
79    value: string;
80    length: number;
81}
82
83interface NumType {
84    type: Types.Num;
85    value: number;
86}
87
88function func2(inst: Instance) {
89    while (true) {
90        switch (inst.type) {
91            case Types.Str: {
92                inst.value.length;
93                break;
94            }
95            case Types.Num: {
96                inst.value.toExponential;
97                break;
98            }
99        }
100    }
101}
102
103// Repro from #29106
104
105const f = (_a: string, _b: string): void => {};
106
107interface A {
108  a?: string;
109  b?: string;
110}
111
112interface B {
113  a: string;
114  b: string;
115}
116
117type U = A | B;
118
119const u: U = {} as any;
120
121u.a && u.b && f(u.a, u.b);
122
123u.b && u.a && f(u.a, u.b);
124
125// Repro from #29012
126
127type Additive = '+' | '-';
128type Multiplicative = '*' | '/';
129
130interface AdditiveObj {
131    key: Additive
132}
133
134interface MultiplicativeObj {
135    key: Multiplicative
136}
137
138type Obj = AdditiveObj | MultiplicativeObj
139
140export function foo(obj: Obj) {
141    switch (obj.key) {
142        case '+': {
143            onlyPlus(obj.key);
144            return;
145        }
146    }
147}
148
149function onlyPlus(arg: '+') {
150  return arg;
151}
152
153// Repro from #29496
154
155declare function never(value: never): never;
156
157const enum BarEnum {
158    bar1 = 1,
159    bar2 = 2,
160}
161
162type UnionOfBar = TypeBar1 | TypeBar2;
163type TypeBar1 = { type: BarEnum.bar1 };
164type TypeBar2 = { type: BarEnum.bar2 };
165
166function func3(value: Partial<UnionOfBar>) {
167    if (value.type !== undefined) {
168        switch (value.type) {
169            case BarEnum.bar1:
170                break;
171            case BarEnum.bar2:
172                break;
173            default:
174                never(value.type);
175        }
176    }
177}
178
179// Repro from #30557
180
181interface TypeA {
182    Name: "TypeA";
183    Value1: "Cool stuff!";
184}
185
186interface TypeB {
187    Name: "TypeB";
188    Value2: 0;
189}
190
191type Type = TypeA | TypeB;
192
193declare function isType(x: unknown): x is Type;
194
195function WorksProperly(data: Type) {
196    if (data.Name === "TypeA") {
197        const value1 = data.Value1;
198    }
199}
200
201function DoesNotWork(data: unknown) {
202    if (isType(data)) {
203        if (data.Name === "TypeA") {
204            const value1 = data.Value1;
205        }
206    }
207}
208
209// Repro from #36777
210
211type TestA = {
212    type: 'testA';
213    bananas: 3;
214}
215
216type TestB = {
217    type: 'testB';
218    apples: 5;
219}
220
221type AllTests = TestA | TestB;
222
223type MapOfAllTests = Record<string, AllTests>;
224
225const doTestingStuff = (mapOfTests: MapOfAllTests, ids: string[]) => {
226    ids.forEach(id => {
227        let test;
228        test = mapOfTests[id];
229        if (test.type === 'testA') {
230            console.log(test.bananas);
231        }
232        switch (test.type) {
233            case 'testA': {
234                console.log(test.bananas);
235            }
236        }
237    });
238};
239