Skip to content

Commit 16d2eb7

Browse files
authored
Error on this.xxx access of previously declared but uninitialized property (microsoft#38030)
* Error on this.xxx access of previously declared but uninitialized property * Add tests * Accept new baselines
1 parent 9d8a70c commit 16d2eb7

8 files changed

+431
-2
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1364,7 +1364,7 @@ namespace ts {
13641364
return sourceFiles.indexOf(declarationFile) <= sourceFiles.indexOf(useFile);
13651365
}
13661366

1367-
if (declaration.pos <= usage.pos) {
1367+
if (declaration.pos <= usage.pos && !(isPropertyDeclaration(declaration) && isThisProperty(usage.parent) && !declaration.initializer && !declaration.exclamationToken)) {
13681368
// declaration is before usage
13691369
if (declaration.kind === SyntaxKind.BindingElement) {
13701370
// still might be illegal if declaration and usage are both binding elements (eg var [a = b, b = b] = [1, 2])

tests/baselines/reference/abstractPropertyInConstructor.errors.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ tests/cases/compiler/abstractPropertyInConstructor.ts(4,24): error TS2715: Abstr
22
tests/cases/compiler/abstractPropertyInConstructor.ts(7,18): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
33
tests/cases/compiler/abstractPropertyInConstructor.ts(9,14): error TS2715: Abstract property 'cb' in class 'AbstractClass' cannot be accessed in the constructor.
44
tests/cases/compiler/abstractPropertyInConstructor.ts(25,18): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
5+
tests/cases/compiler/abstractPropertyInConstructor.ts(25,18): error TS2729: Property 'prop' is used before its initialization.
56
tests/cases/compiler/abstractPropertyInConstructor.ts(39,22): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
67

78

8-
==== tests/cases/compiler/abstractPropertyInConstructor.ts (5 errors) ====
9+
==== tests/cases/compiler/abstractPropertyInConstructor.ts (6 errors) ====
910
abstract class AbstractClass {
1011
constructor(str: string, other: AbstractClass) {
1112
this.method(parseInt(str));
@@ -39,6 +40,9 @@ tests/cases/compiler/abstractPropertyInConstructor.ts(39,22): error TS2715: Abst
3940
other = this.prop;
4041
~~~~
4142
!!! error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
43+
~~~~
44+
!!! error TS2729: Property 'prop' is used before its initialization.
45+
!!! related TS2728 tests/cases/compiler/abstractPropertyInConstructor.ts:20:14: 'prop' is declared here.
4246
fn = () => this.prop;
4347

4448
method2() {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
tests/cases/compiler/initializerWithThisPropertyAccess.ts(3,14): error TS2729: Property 'a' is used before its initialization.
2+
tests/cases/compiler/initializerWithThisPropertyAccess.ts(24,29): error TS2729: Property 'bar' is used before its initialization.
3+
4+
5+
==== tests/cases/compiler/initializerWithThisPropertyAccess.ts (2 errors) ====
6+
class A {
7+
a: number;
8+
b = this.a; // Error
9+
~
10+
!!! error TS2729: Property 'a' is used before its initialization.
11+
!!! related TS2728 tests/cases/compiler/initializerWithThisPropertyAccess.ts:2:5: 'a' is declared here.
12+
c = () => this.a;
13+
d = (new A()).a;
14+
constructor() {
15+
this.a = 1;
16+
}
17+
}
18+
19+
class B extends A {
20+
x = this.a;
21+
}
22+
23+
class C {
24+
a!: number;
25+
b = this.a;
26+
}
27+
28+
// Repro from #37979
29+
30+
class Foo {
31+
private bar: Bar;
32+
readonly barProp = this.bar.prop;
33+
~~~
34+
!!! error TS2729: Property 'bar' is used before its initialization.
35+
!!! related TS2728 tests/cases/compiler/initializerWithThisPropertyAccess.ts:23:13: 'bar' is declared here.
36+
constructor() {
37+
this.bar = new Bar();
38+
}
39+
}
40+
41+
class Bar {
42+
readonly prop = false;
43+
}
44+
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
//// [initializerWithThisPropertyAccess.ts]
2+
class A {
3+
a: number;
4+
b = this.a; // Error
5+
c = () => this.a;
6+
d = (new A()).a;
7+
constructor() {
8+
this.a = 1;
9+
}
10+
}
11+
12+
class B extends A {
13+
x = this.a;
14+
}
15+
16+
class C {
17+
a!: number;
18+
b = this.a;
19+
}
20+
21+
// Repro from #37979
22+
23+
class Foo {
24+
private bar: Bar;
25+
readonly barProp = this.bar.prop;
26+
constructor() {
27+
this.bar = new Bar();
28+
}
29+
}
30+
31+
class Bar {
32+
readonly prop = false;
33+
}
34+
35+
36+
//// [initializerWithThisPropertyAccess.js]
37+
"use strict";
38+
var __extends = (this && this.__extends) || (function () {
39+
var extendStatics = function (d, b) {
40+
extendStatics = Object.setPrototypeOf ||
41+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
42+
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
43+
return extendStatics(d, b);
44+
};
45+
return function (d, b) {
46+
extendStatics(d, b);
47+
function __() { this.constructor = d; }
48+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
49+
};
50+
})();
51+
var A = /** @class */ (function () {
52+
function A() {
53+
var _this = this;
54+
this.b = this.a; // Error
55+
this.c = function () { return _this.a; };
56+
this.d = (new A()).a;
57+
this.a = 1;
58+
}
59+
return A;
60+
}());
61+
var B = /** @class */ (function (_super) {
62+
__extends(B, _super);
63+
function B() {
64+
var _this = _super !== null && _super.apply(this, arguments) || this;
65+
_this.x = _this.a;
66+
return _this;
67+
}
68+
return B;
69+
}(A));
70+
var C = /** @class */ (function () {
71+
function C() {
72+
this.b = this.a;
73+
}
74+
return C;
75+
}());
76+
// Repro from #37979
77+
var Foo = /** @class */ (function () {
78+
function Foo() {
79+
this.barProp = this.bar.prop;
80+
this.bar = new Bar();
81+
}
82+
return Foo;
83+
}());
84+
var Bar = /** @class */ (function () {
85+
function Bar() {
86+
this.prop = false;
87+
}
88+
return Bar;
89+
}());
90+
91+
92+
//// [initializerWithThisPropertyAccess.d.ts]
93+
declare class A {
94+
a: number;
95+
b: number;
96+
c: () => number;
97+
d: number;
98+
constructor();
99+
}
100+
declare class B extends A {
101+
x: number;
102+
}
103+
declare class C {
104+
a: number;
105+
b: number;
106+
}
107+
declare class Foo {
108+
private bar;
109+
readonly barProp = false;
110+
constructor();
111+
}
112+
declare class Bar {
113+
readonly prop = false;
114+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
=== tests/cases/compiler/initializerWithThisPropertyAccess.ts ===
2+
class A {
3+
>A : Symbol(A, Decl(initializerWithThisPropertyAccess.ts, 0, 0))
4+
5+
a: number;
6+
>a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
7+
8+
b = this.a; // Error
9+
>b : Symbol(A.b, Decl(initializerWithThisPropertyAccess.ts, 1, 14))
10+
>this.a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
11+
>this : Symbol(A, Decl(initializerWithThisPropertyAccess.ts, 0, 0))
12+
>a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
13+
14+
c = () => this.a;
15+
>c : Symbol(A.c, Decl(initializerWithThisPropertyAccess.ts, 2, 15))
16+
>this.a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
17+
>this : Symbol(A, Decl(initializerWithThisPropertyAccess.ts, 0, 0))
18+
>a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
19+
20+
d = (new A()).a;
21+
>d : Symbol(A.d, Decl(initializerWithThisPropertyAccess.ts, 3, 21))
22+
>(new A()).a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
23+
>A : Symbol(A, Decl(initializerWithThisPropertyAccess.ts, 0, 0))
24+
>a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
25+
26+
constructor() {
27+
this.a = 1;
28+
>this.a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
29+
>this : Symbol(A, Decl(initializerWithThisPropertyAccess.ts, 0, 0))
30+
>a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
31+
}
32+
}
33+
34+
class B extends A {
35+
>B : Symbol(B, Decl(initializerWithThisPropertyAccess.ts, 8, 1))
36+
>A : Symbol(A, Decl(initializerWithThisPropertyAccess.ts, 0, 0))
37+
38+
x = this.a;
39+
>x : Symbol(B.x, Decl(initializerWithThisPropertyAccess.ts, 10, 19))
40+
>this.a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
41+
>this : Symbol(B, Decl(initializerWithThisPropertyAccess.ts, 8, 1))
42+
>a : Symbol(A.a, Decl(initializerWithThisPropertyAccess.ts, 0, 9))
43+
}
44+
45+
class C {
46+
>C : Symbol(C, Decl(initializerWithThisPropertyAccess.ts, 12, 1))
47+
48+
a!: number;
49+
>a : Symbol(C.a, Decl(initializerWithThisPropertyAccess.ts, 14, 9))
50+
51+
b = this.a;
52+
>b : Symbol(C.b, Decl(initializerWithThisPropertyAccess.ts, 15, 15))
53+
>this.a : Symbol(C.a, Decl(initializerWithThisPropertyAccess.ts, 14, 9))
54+
>this : Symbol(C, Decl(initializerWithThisPropertyAccess.ts, 12, 1))
55+
>a : Symbol(C.a, Decl(initializerWithThisPropertyAccess.ts, 14, 9))
56+
}
57+
58+
// Repro from #37979
59+
60+
class Foo {
61+
>Foo : Symbol(Foo, Decl(initializerWithThisPropertyAccess.ts, 17, 1))
62+
63+
private bar: Bar;
64+
>bar : Symbol(Foo.bar, Decl(initializerWithThisPropertyAccess.ts, 21, 11))
65+
>Bar : Symbol(Bar, Decl(initializerWithThisPropertyAccess.ts, 27, 1))
66+
67+
readonly barProp = this.bar.prop;
68+
>barProp : Symbol(Foo.barProp, Decl(initializerWithThisPropertyAccess.ts, 22, 21))
69+
>this.bar.prop : Symbol(Bar.prop, Decl(initializerWithThisPropertyAccess.ts, 29, 11))
70+
>this.bar : Symbol(Foo.bar, Decl(initializerWithThisPropertyAccess.ts, 21, 11))
71+
>this : Symbol(Foo, Decl(initializerWithThisPropertyAccess.ts, 17, 1))
72+
>bar : Symbol(Foo.bar, Decl(initializerWithThisPropertyAccess.ts, 21, 11))
73+
>prop : Symbol(Bar.prop, Decl(initializerWithThisPropertyAccess.ts, 29, 11))
74+
75+
constructor() {
76+
this.bar = new Bar();
77+
>this.bar : Symbol(Foo.bar, Decl(initializerWithThisPropertyAccess.ts, 21, 11))
78+
>this : Symbol(Foo, Decl(initializerWithThisPropertyAccess.ts, 17, 1))
79+
>bar : Symbol(Foo.bar, Decl(initializerWithThisPropertyAccess.ts, 21, 11))
80+
>Bar : Symbol(Bar, Decl(initializerWithThisPropertyAccess.ts, 27, 1))
81+
}
82+
}
83+
84+
class Bar {
85+
>Bar : Symbol(Bar, Decl(initializerWithThisPropertyAccess.ts, 27, 1))
86+
87+
readonly prop = false;
88+
>prop : Symbol(Bar.prop, Decl(initializerWithThisPropertyAccess.ts, 29, 11))
89+
}
90+
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
=== tests/cases/compiler/initializerWithThisPropertyAccess.ts ===
2+
class A {
3+
>A : A
4+
5+
a: number;
6+
>a : number
7+
8+
b = this.a; // Error
9+
>b : number
10+
>this.a : number
11+
>this : this
12+
>a : number
13+
14+
c = () => this.a;
15+
>c : () => number
16+
>() => this.a : () => number
17+
>this.a : number
18+
>this : this
19+
>a : number
20+
21+
d = (new A()).a;
22+
>d : number
23+
>(new A()).a : number
24+
>(new A()) : A
25+
>new A() : A
26+
>A : typeof A
27+
>a : number
28+
29+
constructor() {
30+
this.a = 1;
31+
>this.a = 1 : 1
32+
>this.a : number
33+
>this : this
34+
>a : number
35+
>1 : 1
36+
}
37+
}
38+
39+
class B extends A {
40+
>B : B
41+
>A : A
42+
43+
x = this.a;
44+
>x : number
45+
>this.a : number
46+
>this : this
47+
>a : number
48+
}
49+
50+
class C {
51+
>C : C
52+
53+
a!: number;
54+
>a : number
55+
56+
b = this.a;
57+
>b : number
58+
>this.a : number
59+
>this : this
60+
>a : number
61+
}
62+
63+
// Repro from #37979
64+
65+
class Foo {
66+
>Foo : Foo
67+
68+
private bar: Bar;
69+
>bar : Bar
70+
71+
readonly barProp = this.bar.prop;
72+
>barProp : false
73+
>this.bar.prop : false
74+
>this.bar : Bar
75+
>this : this
76+
>bar : Bar
77+
>prop : false
78+
79+
constructor() {
80+
this.bar = new Bar();
81+
>this.bar = new Bar() : Bar
82+
>this.bar : Bar
83+
>this : this
84+
>bar : Bar
85+
>new Bar() : Bar
86+
>Bar : typeof Bar
87+
}
88+
}
89+
90+
class Bar {
91+
>Bar : Bar
92+
93+
readonly prop = false;
94+
>prop : false
95+
>false : false
96+
}
97+

0 commit comments

Comments
 (0)