Skip to content

Commit 335d7c8

Browse files
committed
Add tests
1 parent 9ed6357 commit 335d7c8

9 files changed

+4826
-0
lines changed
Lines changed: 341 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,341 @@
1+
tests/cases/compiler/inKeywordTypeguard.ts(6,11): error TS2339: Property 'b' does not exist on type 'A'.
2+
tests/cases/compiler/inKeywordTypeguard.ts(8,11): error TS2339: Property 'a' does not exist on type 'B'.
3+
tests/cases/compiler/inKeywordTypeguard.ts(14,11): error TS2339: Property 'b' does not exist on type 'A'.
4+
tests/cases/compiler/inKeywordTypeguard.ts(16,11): error TS2339: Property 'a' does not exist on type 'B'.
5+
tests/cases/compiler/inKeywordTypeguard.ts(27,11): error TS2339: Property 'b' does not exist on type 'AWithOptionalProp | BWithOptionalProp'.
6+
Property 'b' does not exist on type 'AWithOptionalProp'.
7+
tests/cases/compiler/inKeywordTypeguard.ts(42,11): error TS2339: Property 'b' does not exist on type 'AWithMethod'.
8+
tests/cases/compiler/inKeywordTypeguard.ts(49,11): error TS2339: Property 'a' does not exist on type '(AWithMethod & Record<"c", unknown>) | (BWithMethod & Record<"c", unknown>)'.
9+
Property 'a' does not exist on type 'BWithMethod & Record<"c", unknown>'.
10+
tests/cases/compiler/inKeywordTypeguard.ts(50,11): error TS2339: Property 'b' does not exist on type '(AWithMethod & Record<"c", unknown>) | (BWithMethod & Record<"c", unknown>)'.
11+
Property 'b' does not exist on type 'AWithMethod & Record<"c", unknown>'.
12+
tests/cases/compiler/inKeywordTypeguard.ts(52,11): error TS2339: Property 'a' does not exist on type 'AWithMethod | BWithMethod'.
13+
Property 'a' does not exist on type 'BWithMethod'.
14+
tests/cases/compiler/inKeywordTypeguard.ts(53,11): error TS2339: Property 'b' does not exist on type 'AWithMethod | BWithMethod'.
15+
Property 'b' does not exist on type 'AWithMethod'.
16+
tests/cases/compiler/inKeywordTypeguard.ts(62,11): error TS2339: Property 'b' does not exist on type 'A | C | D'.
17+
Property 'b' does not exist on type 'A'.
18+
tests/cases/compiler/inKeywordTypeguard.ts(64,11): error TS2339: Property 'a' does not exist on type 'B'.
19+
tests/cases/compiler/inKeywordTypeguard.ts(72,32): error TS2339: Property 'b' does not exist on type 'A'.
20+
tests/cases/compiler/inKeywordTypeguard.ts(74,32): error TS2339: Property 'a' does not exist on type 'B'.
21+
tests/cases/compiler/inKeywordTypeguard.ts(82,39): error TS2339: Property 'b' does not exist on type 'A'.
22+
tests/cases/compiler/inKeywordTypeguard.ts(84,39): error TS2339: Property 'a' does not exist on type 'B'.
23+
tests/cases/compiler/inKeywordTypeguard.ts(94,26): error TS2339: Property 'a' does not exist on type 'never'.
24+
tests/cases/compiler/inKeywordTypeguard.ts(150,16): error TS2339: Property 'ontouchstart' does not exist on type 'never'.
25+
tests/cases/compiler/inKeywordTypeguard.ts(155,16): error TS2322: Type 'unknown' is not assignable to type 'object'.
26+
tests/cases/compiler/inKeywordTypeguard.ts(158,21): error TS2322: Type 'unknown' is not assignable to type 'object'.
27+
tests/cases/compiler/inKeywordTypeguard.ts(183,16): error TS2322: Type 'T' is not assignable to type 'object'.
28+
tests/cases/compiler/inKeywordTypeguard.ts(186,21): error TS2322: Type 'T' is not assignable to type 'object'.
29+
30+
31+
==== tests/cases/compiler/inKeywordTypeguard.ts (22 errors) ====
32+
class A { a: string; }
33+
class B { b: string; }
34+
35+
function negativeClassesTest(x: A | B) {
36+
if ("a" in x) {
37+
x.b = "1";
38+
~
39+
!!! error TS2339: Property 'b' does not exist on type 'A'.
40+
} else {
41+
x.a = "1";
42+
~
43+
!!! error TS2339: Property 'a' does not exist on type 'B'.
44+
}
45+
}
46+
47+
function positiveClassesTest(x: A | B) {
48+
if ("a" in x) {
49+
x.b = "1";
50+
~
51+
!!! error TS2339: Property 'b' does not exist on type 'A'.
52+
} else {
53+
x.a = "1";
54+
~
55+
!!! error TS2339: Property 'a' does not exist on type 'B'.
56+
}
57+
}
58+
59+
class AWithOptionalProp { a?: string; }
60+
class BWithOptionalProp { b?: string; }
61+
62+
function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) {
63+
if ("a" in x) {
64+
x.a = "1";
65+
} else {
66+
x.b = "1";
67+
~
68+
!!! error TS2339: Property 'b' does not exist on type 'AWithOptionalProp | BWithOptionalProp'.
69+
!!! error TS2339: Property 'b' does not exist on type 'AWithOptionalProp'.
70+
}
71+
}
72+
73+
class AWithMethod {
74+
a(): string { return ""; }
75+
}
76+
77+
class BWithMethod {
78+
b(): string { return ""; }
79+
}
80+
81+
function negativeTestClassesWithMembers(x: AWithMethod | BWithMethod) {
82+
if ("a" in x) {
83+
x.a();
84+
x.b();
85+
~
86+
!!! error TS2339: Property 'b' does not exist on type 'AWithMethod'.
87+
} else {
88+
}
89+
}
90+
91+
function negativeTestClassesWithMemberMissingInBothClasses(x: AWithMethod | BWithMethod) {
92+
if ("c" in x) {
93+
x.a();
94+
~
95+
!!! error TS2339: Property 'a' does not exist on type '(AWithMethod & Record<"c", unknown>) | (BWithMethod & Record<"c", unknown>)'.
96+
!!! error TS2339: Property 'a' does not exist on type 'BWithMethod & Record<"c", unknown>'.
97+
x.b();
98+
~
99+
!!! error TS2339: Property 'b' does not exist on type '(AWithMethod & Record<"c", unknown>) | (BWithMethod & Record<"c", unknown>)'.
100+
!!! error TS2339: Property 'b' does not exist on type 'AWithMethod & Record<"c", unknown>'.
101+
} else {
102+
x.a();
103+
~
104+
!!! error TS2339: Property 'a' does not exist on type 'AWithMethod | BWithMethod'.
105+
!!! error TS2339: Property 'a' does not exist on type 'BWithMethod'.
106+
x.b();
107+
~
108+
!!! error TS2339: Property 'b' does not exist on type 'AWithMethod | BWithMethod'.
109+
!!! error TS2339: Property 'b' does not exist on type 'AWithMethod'.
110+
}
111+
}
112+
113+
class C { a: string; }
114+
class D { a: string; }
115+
116+
function negativeMultipleClassesTest(x: A | B | C | D) {
117+
if ("a" in x) {
118+
x.b = "1";
119+
~
120+
!!! error TS2339: Property 'b' does not exist on type 'A | C | D'.
121+
!!! error TS2339: Property 'b' does not exist on type 'A'.
122+
} else {
123+
x.a = "1";
124+
~
125+
!!! error TS2339: Property 'a' does not exist on type 'B'.
126+
}
127+
}
128+
129+
class ClassWithUnionProp { prop: A | B }
130+
131+
function negativePropTest(x: ClassWithUnionProp) {
132+
if ("a" in x.prop) {
133+
let y: string = x.prop.b;
134+
~
135+
!!! error TS2339: Property 'b' does not exist on type 'A'.
136+
} else {
137+
let z: string = x.prop.a;
138+
~
139+
!!! error TS2339: Property 'a' does not exist on type 'B'.
140+
}
141+
}
142+
143+
class NegativeClassTest {
144+
protected prop: A | B;
145+
inThis() {
146+
if ("a" in this.prop) {
147+
let z: number = this.prop.b;
148+
~
149+
!!! error TS2339: Property 'b' does not exist on type 'A'.
150+
} else {
151+
let y: string = this.prop.a;
152+
~
153+
!!! error TS2339: Property 'a' does not exist on type 'B'.
154+
}
155+
}
156+
}
157+
158+
class UnreachableCodeDetection {
159+
a: string;
160+
inThis() {
161+
if ("a" in this) {
162+
} else {
163+
let y = this.a;
164+
~
165+
!!! error TS2339: Property 'a' does not exist on type 'never'.
166+
}
167+
}
168+
}
169+
170+
function positiveIntersectionTest(x: { a: string } & { b: string }) {
171+
if ("a" in x) {
172+
let s: string = x.a;
173+
} else {
174+
let n: never = x;
175+
}
176+
}
177+
178+
// Repro from #38608
179+
declare const error: Error;
180+
if ('extra' in error) {
181+
error // Still Error
182+
} else {
183+
error // Error
184+
}
185+
186+
function narrowsToNever(x: { l: number } | { r: number }) {
187+
let v: number;
188+
if ("l" in x) {
189+
v = x.l;
190+
}
191+
else if ("r" in x) {
192+
v = x.r;
193+
}
194+
else {
195+
v = x
196+
}
197+
return v;
198+
}
199+
200+
type AOrB = { aProp: number } | { bProp: number };
201+
declare function isAOrB(x: unknown): x is AOrB;
202+
203+
declare var x: unknown;
204+
if (isAOrB(x)) {
205+
if ("aProp" in x) {
206+
x.aProp;
207+
}
208+
else if ("bProp" in x) {
209+
x.bProp;
210+
}
211+
// x is never because of the type predicate from unknown
212+
else if ("cProp" in x) {
213+
const _never: never = x;
214+
}
215+
}
216+
217+
function negativeIntersectionTest() {
218+
if ("ontouchstart" in window) {
219+
window.ontouchstart
220+
} else {
221+
window.ontouchstart
222+
~~~~~~~~~~~~
223+
!!! error TS2339: Property 'ontouchstart' does not exist on type 'never'.
224+
}
225+
}
226+
227+
function f1(x: unknown) {
228+
if ("a" in x) {
229+
~
230+
!!! error TS2322: Type 'unknown' is not assignable to type 'object'.
231+
x.a;
232+
}
233+
if (x && "a" in x) {
234+
~
235+
!!! error TS2322: Type 'unknown' is not assignable to type 'object'.
236+
x.a;
237+
}
238+
if (x && typeof x === "object" && "a" in x) {
239+
x.a;
240+
}
241+
if (x && typeof x === "object" && "a" in x && "b" in x && "c" in x) {
242+
x.a;
243+
x.b;
244+
x.c;
245+
}
246+
}
247+
248+
function f2(x: object) {
249+
if ("a" in x) {
250+
x.a;
251+
}
252+
if ("a" in x && "b" in x && "c" in x) {
253+
x.a;
254+
x.b;
255+
x.c;
256+
}
257+
}
258+
259+
function f3<T>(x: T) {
260+
if ("a" in x) {
261+
~
262+
!!! error TS2322: Type 'T' is not assignable to type 'object'.
263+
!!! related TS2208 tests/cases/compiler/inKeywordTypeguard.ts:182:13: This type parameter might need an `extends object` constraint.
264+
x.a;
265+
}
266+
if (x && "a" in x) {
267+
~
268+
!!! error TS2322: Type 'T' is not assignable to type 'object'.
269+
!!! related TS2208 tests/cases/compiler/inKeywordTypeguard.ts:182:13: This type parameter might need an `extends object` constraint.
270+
x.a;
271+
}
272+
if (x && typeof x === "object" && "a" in x) {
273+
x.a;
274+
}
275+
if (x && typeof x === "object" && "a" in x && "b" in x && "c" in x) {
276+
x.a;
277+
x.b;
278+
x.c;
279+
}
280+
}
281+
282+
function f4(x: { a: string }) {
283+
if ("a" in x) {
284+
x.a;
285+
}
286+
if ("a" in x && "b" in x && "c" in x) {
287+
x.a;
288+
x.b;
289+
x.c;
290+
}
291+
}
292+
293+
function f5(x: { a: string } | { b: string }) {
294+
if ("a" in x) {
295+
x; // { a: string }
296+
}
297+
else if ("b" in x) {
298+
x; // { b: string }
299+
}
300+
else {
301+
x; // never
302+
}
303+
}
304+
305+
function f6(x: { a: string } | { b: string }) {
306+
if ("a" in x) {
307+
x; // { a: string }
308+
}
309+
else if ("a" in x) {
310+
x; // { b: string } & Record<"a", unknown>
311+
}
312+
else {
313+
x; // { b: string }
314+
}
315+
}
316+
317+
// Object and corresponding intersection should narrow the same
318+
319+
function f7(x: { a: string, b: number }, y: { a: string } & { b: number }) {
320+
if ("a" in x) {
321+
x;
322+
}
323+
else {
324+
x; // never
325+
}
326+
if ("a" in y) {
327+
y;
328+
}
329+
else {
330+
y; // never
331+
}
332+
}
333+
334+
// Repro from #50639
335+
336+
function f8<A>(value: A) {
337+
if (typeof value === "object" && value !== null && "prop" in value) {
338+
value; // A & object & Record<"prop", unknown>
339+
}
340+
}
341+

0 commit comments

Comments
 (0)