Skip to content

Commit 3d55456

Browse files
Merge pull request #13230 from Microsoft/instanceofRelationshipTargetTypes
Check if uninstantiated types are the same when narrowing by instanceof
2 parents abc9b0d + e535c0c commit 3d55456

File tree

6 files changed

+276
-1
lines changed

6 files changed

+276
-1
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6920,7 +6920,7 @@ namespace ts {
69206920
// subtype of T but not structurally identical to T. This specifically means that two distinct but
69216921
// structurally identical types (such as two classes) are not considered instances of each other.
69226922
function isTypeInstanceOf(source: Type, target: Type): boolean {
6923-
return source === target || isTypeSubtypeOf(source, target) && !isTypeIdenticalTo(source, target);
6923+
return getTargetType(source) === getTargetType(target) || isTypeSubtypeOf(source, target) && !isTypeIdenticalTo(source, target);
69246924
}
69256925

69266926
/**
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
tests/cases/conformance/types/typeRelationships/instanceOf/narrowingGenericTypeFromInstanceof01.ts(13,17): error TS2345: Argument of type 'A<T> | B<T>' is not assignable to parameter of type 'A<T>'.
2+
Type 'B<T>' is not assignable to type 'A<T>'.
3+
Property 'a' is missing in type 'B<T>'.
4+
5+
6+
==== tests/cases/conformance/types/typeRelationships/instanceOf/narrowingGenericTypeFromInstanceof01.ts (1 errors) ====
7+
class A<T> {
8+
constructor(private a: string) { }
9+
}
10+
11+
class B<T> {
12+
}
13+
14+
function acceptA<T>(a: A<T>) { }
15+
function acceptB<T>(b: B<T>) { }
16+
17+
function test<T>(x: A<T> | B<T>) {
18+
if (x instanceof B) {
19+
acceptA(x);
20+
~
21+
!!! error TS2345: Argument of type 'A<T> | B<T>' is not assignable to parameter of type 'A<T>'.
22+
!!! error TS2345: Type 'B<T>' is not assignable to type 'A<T>'.
23+
!!! error TS2345: Property 'a' is missing in type 'B<T>'.
24+
}
25+
26+
if (x instanceof A) {
27+
acceptA(x);
28+
}
29+
30+
if (x instanceof B) {
31+
acceptB(x);
32+
}
33+
34+
if (x instanceof B) {
35+
acceptB(x);
36+
}
37+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//// [narrowingGenericTypeFromInstanceof01.ts]
2+
class A<T> {
3+
constructor(private a: string) { }
4+
}
5+
6+
class B<T> {
7+
}
8+
9+
function acceptA<T>(a: A<T>) { }
10+
function acceptB<T>(b: B<T>) { }
11+
12+
function test<T>(x: A<T> | B<T>) {
13+
if (x instanceof B) {
14+
acceptA(x);
15+
}
16+
17+
if (x instanceof A) {
18+
acceptA(x);
19+
}
20+
21+
if (x instanceof B) {
22+
acceptB(x);
23+
}
24+
25+
if (x instanceof B) {
26+
acceptB(x);
27+
}
28+
}
29+
30+
//// [narrowingGenericTypeFromInstanceof01.js]
31+
var A = (function () {
32+
function A(a) {
33+
this.a = a;
34+
}
35+
return A;
36+
}());
37+
var B = (function () {
38+
function B() {
39+
}
40+
return B;
41+
}());
42+
function acceptA(a) { }
43+
function acceptB(b) { }
44+
function test(x) {
45+
if (x instanceof B) {
46+
acceptA(x);
47+
}
48+
if (x instanceof A) {
49+
acceptA(x);
50+
}
51+
if (x instanceof B) {
52+
acceptB(x);
53+
}
54+
if (x instanceof B) {
55+
acceptB(x);
56+
}
57+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
=== tests/cases/conformance/types/typeRelationships/instanceOf/narrowingGenericTypeFromInstanceof01.ts ===
2+
class A<T> {
3+
>A : Symbol(A, Decl(narrowingGenericTypeFromInstanceof01.ts, 0, 0))
4+
>T : Symbol(T, Decl(narrowingGenericTypeFromInstanceof01.ts, 0, 8))
5+
6+
constructor(private a: string) { }
7+
>a : Symbol(A.a, Decl(narrowingGenericTypeFromInstanceof01.ts, 1, 16))
8+
}
9+
10+
class B<T> {
11+
>B : Symbol(B, Decl(narrowingGenericTypeFromInstanceof01.ts, 2, 1))
12+
>T : Symbol(T, Decl(narrowingGenericTypeFromInstanceof01.ts, 4, 8))
13+
}
14+
15+
function acceptA<T>(a: A<T>) { }
16+
>acceptA : Symbol(acceptA, Decl(narrowingGenericTypeFromInstanceof01.ts, 5, 1))
17+
>T : Symbol(T, Decl(narrowingGenericTypeFromInstanceof01.ts, 7, 17))
18+
>a : Symbol(a, Decl(narrowingGenericTypeFromInstanceof01.ts, 7, 20))
19+
>A : Symbol(A, Decl(narrowingGenericTypeFromInstanceof01.ts, 0, 0))
20+
>T : Symbol(T, Decl(narrowingGenericTypeFromInstanceof01.ts, 7, 17))
21+
22+
function acceptB<T>(b: B<T>) { }
23+
>acceptB : Symbol(acceptB, Decl(narrowingGenericTypeFromInstanceof01.ts, 7, 32))
24+
>T : Symbol(T, Decl(narrowingGenericTypeFromInstanceof01.ts, 8, 17))
25+
>b : Symbol(b, Decl(narrowingGenericTypeFromInstanceof01.ts, 8, 20))
26+
>B : Symbol(B, Decl(narrowingGenericTypeFromInstanceof01.ts, 2, 1))
27+
>T : Symbol(T, Decl(narrowingGenericTypeFromInstanceof01.ts, 8, 17))
28+
29+
function test<T>(x: A<T> | B<T>) {
30+
>test : Symbol(test, Decl(narrowingGenericTypeFromInstanceof01.ts, 8, 32))
31+
>T : Symbol(T, Decl(narrowingGenericTypeFromInstanceof01.ts, 10, 14))
32+
>x : Symbol(x, Decl(narrowingGenericTypeFromInstanceof01.ts, 10, 17))
33+
>A : Symbol(A, Decl(narrowingGenericTypeFromInstanceof01.ts, 0, 0))
34+
>T : Symbol(T, Decl(narrowingGenericTypeFromInstanceof01.ts, 10, 14))
35+
>B : Symbol(B, Decl(narrowingGenericTypeFromInstanceof01.ts, 2, 1))
36+
>T : Symbol(T, Decl(narrowingGenericTypeFromInstanceof01.ts, 10, 14))
37+
38+
if (x instanceof B) {
39+
>x : Symbol(x, Decl(narrowingGenericTypeFromInstanceof01.ts, 10, 17))
40+
>B : Symbol(B, Decl(narrowingGenericTypeFromInstanceof01.ts, 2, 1))
41+
42+
acceptA(x);
43+
>acceptA : Symbol(acceptA, Decl(narrowingGenericTypeFromInstanceof01.ts, 5, 1))
44+
>x : Symbol(x, Decl(narrowingGenericTypeFromInstanceof01.ts, 10, 17))
45+
}
46+
47+
if (x instanceof A) {
48+
>x : Symbol(x, Decl(narrowingGenericTypeFromInstanceof01.ts, 10, 17))
49+
>A : Symbol(A, Decl(narrowingGenericTypeFromInstanceof01.ts, 0, 0))
50+
51+
acceptA(x);
52+
>acceptA : Symbol(acceptA, Decl(narrowingGenericTypeFromInstanceof01.ts, 5, 1))
53+
>x : Symbol(x, Decl(narrowingGenericTypeFromInstanceof01.ts, 10, 17))
54+
}
55+
56+
if (x instanceof B) {
57+
>x : Symbol(x, Decl(narrowingGenericTypeFromInstanceof01.ts, 10, 17))
58+
>B : Symbol(B, Decl(narrowingGenericTypeFromInstanceof01.ts, 2, 1))
59+
60+
acceptB(x);
61+
>acceptB : Symbol(acceptB, Decl(narrowingGenericTypeFromInstanceof01.ts, 7, 32))
62+
>x : Symbol(x, Decl(narrowingGenericTypeFromInstanceof01.ts, 10, 17))
63+
}
64+
65+
if (x instanceof B) {
66+
>x : Symbol(x, Decl(narrowingGenericTypeFromInstanceof01.ts, 10, 17))
67+
>B : Symbol(B, Decl(narrowingGenericTypeFromInstanceof01.ts, 2, 1))
68+
69+
acceptB(x);
70+
>acceptB : Symbol(acceptB, Decl(narrowingGenericTypeFromInstanceof01.ts, 7, 32))
71+
>x : Symbol(x, Decl(narrowingGenericTypeFromInstanceof01.ts, 10, 17))
72+
}
73+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
=== tests/cases/conformance/types/typeRelationships/instanceOf/narrowingGenericTypeFromInstanceof01.ts ===
2+
class A<T> {
3+
>A : A<T>
4+
>T : T
5+
6+
constructor(private a: string) { }
7+
>a : string
8+
}
9+
10+
class B<T> {
11+
>B : B<T>
12+
>T : T
13+
}
14+
15+
function acceptA<T>(a: A<T>) { }
16+
>acceptA : <T>(a: A<T>) => void
17+
>T : T
18+
>a : A<T>
19+
>A : A<T>
20+
>T : T
21+
22+
function acceptB<T>(b: B<T>) { }
23+
>acceptB : <T>(b: B<T>) => void
24+
>T : T
25+
>b : B<T>
26+
>B : B<T>
27+
>T : T
28+
29+
function test<T>(x: A<T> | B<T>) {
30+
>test : <T>(x: A<T> | B<T>) => void
31+
>T : T
32+
>x : A<T> | B<T>
33+
>A : A<T>
34+
>T : T
35+
>B : B<T>
36+
>T : T
37+
38+
if (x instanceof B) {
39+
>x instanceof B : boolean
40+
>x : A<T> | B<T>
41+
>B : typeof B
42+
43+
acceptA(x);
44+
>acceptA(x) : void
45+
>acceptA : <T>(a: A<T>) => void
46+
>x : A<T>
47+
}
48+
49+
if (x instanceof A) {
50+
>x instanceof A : boolean
51+
>x : A<T> | B<T>
52+
>A : typeof A
53+
54+
acceptA(x);
55+
>acceptA(x) : void
56+
>acceptA : <T>(a: A<T>) => void
57+
>x : A<any>
58+
}
59+
60+
if (x instanceof B) {
61+
>x instanceof B : boolean
62+
>x : A<T> | B<T>
63+
>B : typeof B
64+
65+
acceptB(x);
66+
>acceptB(x) : void
67+
>acceptB : <T>(b: B<T>) => void
68+
>x : A<T>
69+
}
70+
71+
if (x instanceof B) {
72+
>x instanceof B : boolean
73+
>x : A<T> | B<T>
74+
>B : typeof B
75+
76+
acceptB(x);
77+
>acceptB(x) : void
78+
>acceptB : <T>(b: B<T>) => void
79+
>x : A<T>
80+
}
81+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
class A<T> {
2+
constructor(private a: string) { }
3+
}
4+
5+
class B<T> {
6+
}
7+
8+
function acceptA<T>(a: A<T>) { }
9+
function acceptB<T>(b: B<T>) { }
10+
11+
function test<T>(x: A<T> | B<T>) {
12+
if (x instanceof B) {
13+
acceptA(x);
14+
}
15+
16+
if (x instanceof A) {
17+
acceptA(x);
18+
}
19+
20+
if (x instanceof B) {
21+
acceptB(x);
22+
}
23+
24+
if (x instanceof B) {
25+
acceptB(x);
26+
}
27+
}

0 commit comments

Comments
 (0)