Skip to content

Commit a0abadb

Browse files
authored
Merge pull request #15320 from Microsoft/fixTypePredicateThisParameter
Fix type predicates with this parameters
2 parents 5783435 + 85d4593 commit a0abadb

File tree

5 files changed

+204
-1
lines changed

5 files changed

+204
-1
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11565,7 +11565,7 @@ namespace ts {
1156511565
}
1156611566

1156711567
if (isIdentifierTypePredicate(predicate)) {
11568-
const predicateArgument = callExpression.arguments[predicate.parameterIndex];
11568+
const predicateArgument = callExpression.arguments[predicate.parameterIndex - (signature.thisParameter ? 1 : 0)];
1156911569
if (predicateArgument) {
1157011570
if (isMatchingReference(reference, predicateArgument)) {
1157111571
return getNarrowedType(type, predicate.type, assumeTrue, isTypeSubtypeOf);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//// [typePredicateWithThisParameter.ts]
2+
// Repro from #15310
3+
4+
interface Foo {
5+
foo: string;
6+
}
7+
interface Bar {
8+
bar: string;
9+
}
10+
11+
function isFoo1(object: {}): object is Foo {
12+
return 'foo' in object;
13+
}
14+
15+
function isFoo2(this: void, object: {}): object is Foo {
16+
return 'foo' in object;
17+
}
18+
19+
declare let test: Foo | Bar;
20+
21+
if (isFoo1(test)) {
22+
test.foo = 'hi';
23+
}
24+
25+
if (isFoo2(test)) {
26+
test.foo = 'hi';
27+
}
28+
29+
30+
//// [typePredicateWithThisParameter.js]
31+
// Repro from #15310
32+
function isFoo1(object) {
33+
return 'foo' in object;
34+
}
35+
function isFoo2(object) {
36+
return 'foo' in object;
37+
}
38+
if (isFoo1(test)) {
39+
test.foo = 'hi';
40+
}
41+
if (isFoo2(test)) {
42+
test.foo = 'hi';
43+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
=== tests/cases/compiler/typePredicateWithThisParameter.ts ===
2+
// Repro from #15310
3+
4+
interface Foo {
5+
>Foo : Symbol(Foo, Decl(typePredicateWithThisParameter.ts, 0, 0))
6+
7+
foo: string;
8+
>foo : Symbol(Foo.foo, Decl(typePredicateWithThisParameter.ts, 2, 15))
9+
}
10+
interface Bar {
11+
>Bar : Symbol(Bar, Decl(typePredicateWithThisParameter.ts, 4, 1))
12+
13+
bar: string;
14+
>bar : Symbol(Bar.bar, Decl(typePredicateWithThisParameter.ts, 5, 15))
15+
}
16+
17+
function isFoo1(object: {}): object is Foo {
18+
>isFoo1 : Symbol(isFoo1, Decl(typePredicateWithThisParameter.ts, 7, 1))
19+
>object : Symbol(object, Decl(typePredicateWithThisParameter.ts, 9, 16))
20+
>object : Symbol(object, Decl(typePredicateWithThisParameter.ts, 9, 16))
21+
>Foo : Symbol(Foo, Decl(typePredicateWithThisParameter.ts, 0, 0))
22+
23+
return 'foo' in object;
24+
>object : Symbol(object, Decl(typePredicateWithThisParameter.ts, 9, 16))
25+
}
26+
27+
function isFoo2(this: void, object: {}): object is Foo {
28+
>isFoo2 : Symbol(isFoo2, Decl(typePredicateWithThisParameter.ts, 11, 1))
29+
>this : Symbol(this, Decl(typePredicateWithThisParameter.ts, 13, 16))
30+
>object : Symbol(object, Decl(typePredicateWithThisParameter.ts, 13, 27))
31+
>object : Symbol(object, Decl(typePredicateWithThisParameter.ts, 13, 27))
32+
>Foo : Symbol(Foo, Decl(typePredicateWithThisParameter.ts, 0, 0))
33+
34+
return 'foo' in object;
35+
>object : Symbol(object, Decl(typePredicateWithThisParameter.ts, 13, 27))
36+
}
37+
38+
declare let test: Foo | Bar;
39+
>test : Symbol(test, Decl(typePredicateWithThisParameter.ts, 17, 11))
40+
>Foo : Symbol(Foo, Decl(typePredicateWithThisParameter.ts, 0, 0))
41+
>Bar : Symbol(Bar, Decl(typePredicateWithThisParameter.ts, 4, 1))
42+
43+
if (isFoo1(test)) {
44+
>isFoo1 : Symbol(isFoo1, Decl(typePredicateWithThisParameter.ts, 7, 1))
45+
>test : Symbol(test, Decl(typePredicateWithThisParameter.ts, 17, 11))
46+
47+
test.foo = 'hi';
48+
>test.foo : Symbol(Foo.foo, Decl(typePredicateWithThisParameter.ts, 2, 15))
49+
>test : Symbol(test, Decl(typePredicateWithThisParameter.ts, 17, 11))
50+
>foo : Symbol(Foo.foo, Decl(typePredicateWithThisParameter.ts, 2, 15))
51+
}
52+
53+
if (isFoo2(test)) {
54+
>isFoo2 : Symbol(isFoo2, Decl(typePredicateWithThisParameter.ts, 11, 1))
55+
>test : Symbol(test, Decl(typePredicateWithThisParameter.ts, 17, 11))
56+
57+
test.foo = 'hi';
58+
>test.foo : Symbol(Foo.foo, Decl(typePredicateWithThisParameter.ts, 2, 15))
59+
>test : Symbol(test, Decl(typePredicateWithThisParameter.ts, 17, 11))
60+
>foo : Symbol(Foo.foo, Decl(typePredicateWithThisParameter.ts, 2, 15))
61+
}
62+
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
=== tests/cases/compiler/typePredicateWithThisParameter.ts ===
2+
// Repro from #15310
3+
4+
interface Foo {
5+
>Foo : Foo
6+
7+
foo: string;
8+
>foo : string
9+
}
10+
interface Bar {
11+
>Bar : Bar
12+
13+
bar: string;
14+
>bar : string
15+
}
16+
17+
function isFoo1(object: {}): object is Foo {
18+
>isFoo1 : (object: {}) => object is Foo
19+
>object : {}
20+
>object : any
21+
>Foo : Foo
22+
23+
return 'foo' in object;
24+
>'foo' in object : boolean
25+
>'foo' : "foo"
26+
>object : {}
27+
}
28+
29+
function isFoo2(this: void, object: {}): object is Foo {
30+
>isFoo2 : (this: void, object: {}) => object is Foo
31+
>this : void
32+
>object : {}
33+
>object : any
34+
>Foo : Foo
35+
36+
return 'foo' in object;
37+
>'foo' in object : boolean
38+
>'foo' : "foo"
39+
>object : {}
40+
}
41+
42+
declare let test: Foo | Bar;
43+
>test : Foo | Bar
44+
>Foo : Foo
45+
>Bar : Bar
46+
47+
if (isFoo1(test)) {
48+
>isFoo1(test) : boolean
49+
>isFoo1 : (object: {}) => object is Foo
50+
>test : Foo | Bar
51+
52+
test.foo = 'hi';
53+
>test.foo = 'hi' : "hi"
54+
>test.foo : string
55+
>test : Foo
56+
>foo : string
57+
>'hi' : "hi"
58+
}
59+
60+
if (isFoo2(test)) {
61+
>isFoo2(test) : boolean
62+
>isFoo2 : (this: void, object: {}) => object is Foo
63+
>test : Foo | Bar
64+
65+
test.foo = 'hi';
66+
>test.foo = 'hi' : "hi"
67+
>test.foo : string
68+
>test : Foo
69+
>foo : string
70+
>'hi' : "hi"
71+
}
72+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Repro from #15310
2+
3+
interface Foo {
4+
foo: string;
5+
}
6+
interface Bar {
7+
bar: string;
8+
}
9+
10+
function isFoo1(object: {}): object is Foo {
11+
return 'foo' in object;
12+
}
13+
14+
function isFoo2(this: void, object: {}): object is Foo {
15+
return 'foo' in object;
16+
}
17+
18+
declare let test: Foo | Bar;
19+
20+
if (isFoo1(test)) {
21+
test.foo = 'hi';
22+
}
23+
24+
if (isFoo2(test)) {
25+
test.foo = 'hi';
26+
}

0 commit comments

Comments
 (0)