Skip to content

Commit 54f7666

Browse files
Merge pull request #26453 from ajafff/abstract-property-in-initializer
disallow abstract property access in property initializer
2 parents 270ea77 + beed179 commit 54f7666

File tree

6 files changed

+53
-14
lines changed

6 files changed

+53
-14
lines changed

src/compiler/checker.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17983,7 +17983,7 @@ namespace ts {
1798317983
// Referencing abstract properties within their own constructors is not allowed
1798417984
if ((flags & ModifierFlags.Abstract) && isThisProperty(node) && symbolHasNonMethodDeclaration(prop)) {
1798517985
const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop)!);
17986-
if (declaringClassDeclaration && isNodeWithinConstructorOfClass(node, declaringClassDeclaration)) {
17986+
if (declaringClassDeclaration && isNodeUsedDuringClassInitialization(node, declaringClassDeclaration)) {
1798717987
error(errorNode, Diagnostics.Abstract_property_0_in_class_1_cannot_be_accessed_in_the_constructor, symbolToString(prop), getTextOfIdentifierOrLiteral(declaringClassDeclaration.name!)); // TODO: GH#18217
1798817988
return false;
1798917989
}
@@ -27117,9 +27117,9 @@ namespace ts {
2711727117
return result;
2711827118
}
2711927119

27120-
function isNodeWithinConstructorOfClass(node: Node, classDeclaration: ClassLikeDeclaration) {
27121-
return findAncestor(node, element => {
27122-
if (isConstructorDeclaration(element) && nodeIsPresent(element.body) && element.parent === classDeclaration) {
27120+
function isNodeUsedDuringClassInitialization(node: Node, classDeclaration: ClassLikeDeclaration) {
27121+
return !!findAncestor(node, element => {
27122+
if ((isConstructorDeclaration(element) && nodeIsPresent(element.body) || isPropertyDeclaration(element)) && element.parent === classDeclaration) {
2712327123
return true;
2712427124
}
2712527125
else if (element === classDeclaration || isFunctionLikeDeclaration(element)) {

tests/baselines/reference/abstractPropertyInConstructor.errors.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
tests/cases/compiler/abstractPropertyInConstructor.ts(4,24): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
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.
4+
tests/cases/compiler/abstractPropertyInConstructor.ts(25,18): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
45

56

6-
==== tests/cases/compiler/abstractPropertyInConstructor.ts (3 errors) ====
7+
==== tests/cases/compiler/abstractPropertyInConstructor.ts (4 errors) ====
78
abstract class AbstractClass {
89
constructor(str: string, other: AbstractClass) {
910
this.method(parseInt(str));
@@ -34,6 +35,11 @@ tests/cases/compiler/abstractPropertyInConstructor.ts(9,14): error TS2715: Abstr
3435

3536
abstract method(num: number): void;
3637

38+
other = this.prop;
39+
~~~~
40+
!!! error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
41+
fn = () => this.prop;
42+
3743
method2() {
3844
this.prop = this.prop + "!";
3945
}

tests/baselines/reference/abstractPropertyInConstructor.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ abstract class AbstractClass {
2323

2424
abstract method(num: number): void;
2525

26+
other = this.prop;
27+
fn = () => this.prop;
28+
2629
method2() {
2730
this.prop = this.prop + "!";
2831
}
@@ -42,6 +45,8 @@ class User {
4245
var AbstractClass = /** @class */ (function () {
4346
function AbstractClass(str, other) {
4447
var _this = this;
48+
this.other = this.prop;
49+
this.fn = function () { return _this.prop; };
4550
this.method(parseInt(str));
4651
var val = this.prop.toLowerCase();
4752
if (!str) {

tests/baselines/reference/abstractPropertyInConstructor.symbols

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,20 @@ abstract class AbstractClass {
6767
>method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37))
6868
>num : Symbol(num, Decl(abstractPropertyInConstructor.ts, 22, 20))
6969

70+
other = this.prop;
71+
>other : Symbol(AbstractClass.other, Decl(abstractPropertyInConstructor.ts, 22, 39))
72+
>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
73+
>this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0))
74+
>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
75+
76+
fn = () => this.prop;
77+
>fn : Symbol(AbstractClass.fn, Decl(abstractPropertyInConstructor.ts, 24, 22))
78+
>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
79+
>this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0))
80+
>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
81+
7082
method2() {
71-
>method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 22, 39))
83+
>method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 25, 25))
7284

7385
this.prop = this.prop + "!";
7486
>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
@@ -81,31 +93,31 @@ abstract class AbstractClass {
8193
}
8294

8395
class User {
84-
>User : Symbol(User, Decl(abstractPropertyInConstructor.ts, 27, 1))
96+
>User : Symbol(User, Decl(abstractPropertyInConstructor.ts, 30, 1))
8597

8698
constructor(a: AbstractClass) {
87-
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 30, 16))
99+
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 33, 16))
88100
>AbstractClass : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0))
89101

90102
a.prop;
91103
>a.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
92-
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 30, 16))
104+
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 33, 16))
93105
>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
94106

95107
a.cb("hi");
96108
>a.cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26))
97-
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 30, 16))
109+
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 33, 16))
98110
>cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26))
99111

100112
a.method(12);
101113
>a.method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37))
102-
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 30, 16))
114+
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 33, 16))
103115
>method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37))
104116

105117
a.method2();
106-
>a.method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 22, 39))
107-
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 30, 16))
108-
>method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 22, 39))
118+
>a.method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 25, 25))
119+
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 33, 16))
120+
>method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 25, 25))
109121
}
110122
}
111123

tests/baselines/reference/abstractPropertyInConstructor.types

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,19 @@ abstract class AbstractClass {
7575
>method : (num: number) => void
7676
>num : number
7777

78+
other = this.prop;
79+
>other : string
80+
>this.prop : string
81+
>this : this
82+
>prop : string
83+
84+
fn = () => this.prop;
85+
>fn : () => string
86+
>() => this.prop : () => string
87+
>this.prop : string
88+
>this : this
89+
>prop : string
90+
7891
method2() {
7992
>method2 : () => void
8093

tests/cases/compiler/abstractPropertyInConstructor.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ abstract class AbstractClass {
2222

2323
abstract method(num: number): void;
2424

25+
other = this.prop;
26+
fn = () => this.prop;
27+
2528
method2() {
2629
this.prop = this.prop + "!";
2730
}

0 commit comments

Comments
 (0)