Skip to content

Commit ba76a84

Browse files
Merge pull request #26935 from ajafff/abstract-baseclass-property
Error accessing abstract property in constructor of abstract subclass
2 parents 8ca01df + c203c27 commit ba76a84

6 files changed

+362
-11
lines changed

src/compiler/checker.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18238,7 +18238,7 @@ namespace ts {
1823818238
// Referencing abstract properties within their own constructors is not allowed
1823918239
if ((flags & ModifierFlags.Abstract) && isThisProperty(node) && symbolHasNonMethodDeclaration(prop)) {
1824018240
const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop)!);
18241-
if (declaringClassDeclaration && isNodeUsedDuringClassInitialization(node, declaringClassDeclaration)) {
18241+
if (declaringClassDeclaration && isNodeUsedDuringClassInitialization(node)) {
1824218242
error(errorNode, Diagnostics.Abstract_property_0_in_class_1_cannot_be_accessed_in_the_constructor, symbolToString(prop), getTextOfIdentifierOrLiteral(declaringClassDeclaration.name!)); // TODO: GH#18217
1824318243
return false;
1824418244
}
@@ -27449,12 +27449,12 @@ namespace ts {
2744927449
return result;
2745027450
}
2745127451

27452-
function isNodeUsedDuringClassInitialization(node: Node, classDeclaration: ClassLikeDeclaration) {
27452+
function isNodeUsedDuringClassInitialization(node: Node) {
2745327453
return !!findAncestor(node, element => {
27454-
if ((isConstructorDeclaration(element) && nodeIsPresent(element.body) || isPropertyDeclaration(element)) && element.parent === classDeclaration) {
27454+
if (isConstructorDeclaration(element) && nodeIsPresent(element.body) || isPropertyDeclaration(element)) {
2745527455
return true;
2745627456
}
27457-
else if (element === classDeclaration || isFunctionLikeDeclaration(element)) {
27457+
else if (isClassLike(element) || isFunctionLikeDeclaration(element)) {
2745827458
return "quit";
2745927459
}
2746027460

tests/baselines/reference/abstractPropertyInConstructor.errors.txt

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ 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(39,22): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
56

67

7-
==== tests/cases/compiler/abstractPropertyInConstructor.ts (4 errors) ====
8+
==== tests/cases/compiler/abstractPropertyInConstructor.ts (5 errors) ====
89
abstract class AbstractClass {
910
constructor(str: string, other: AbstractClass) {
1011
this.method(parseInt(str));
@@ -45,6 +46,38 @@ tests/cases/compiler/abstractPropertyInConstructor.ts(25,18): error TS2715: Abst
4546
}
4647
}
4748

49+
abstract class DerivedAbstractClass extends AbstractClass {
50+
cb = (s: string) => {};
51+
52+
constructor(str: string, other: AbstractClass, yetAnother: DerivedAbstractClass) {
53+
super(str, other);
54+
// there is no implementation of 'prop' in any base class
55+
this.cb(this.prop.toLowerCase());
56+
~~~~
57+
!!! error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
58+
59+
this.method(1);
60+
61+
// OK, references are to another instance
62+
other.cb(other.prop);
63+
yetAnother.cb(yetAnother.prop);
64+
}
65+
}
66+
67+
class Implementation extends DerivedAbstractClass {
68+
prop = "";
69+
cb = (s: string) => {};
70+
71+
constructor(str: string, other: AbstractClass, yetAnother: DerivedAbstractClass) {
72+
super(str, other, yetAnother);
73+
this.cb(this.prop);
74+
}
75+
76+
method(n: number) {
77+
this.cb(this.prop + n);
78+
}
79+
}
80+
4881
class User {
4982
constructor(a: AbstractClass) {
5083
a.prop;

tests/baselines/reference/abstractPropertyInConstructor.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,36 @@ abstract class AbstractClass {
3131
}
3232
}
3333

34+
abstract class DerivedAbstractClass extends AbstractClass {
35+
cb = (s: string) => {};
36+
37+
constructor(str: string, other: AbstractClass, yetAnother: DerivedAbstractClass) {
38+
super(str, other);
39+
// there is no implementation of 'prop' in any base class
40+
this.cb(this.prop.toLowerCase());
41+
42+
this.method(1);
43+
44+
// OK, references are to another instance
45+
other.cb(other.prop);
46+
yetAnother.cb(yetAnother.prop);
47+
}
48+
}
49+
50+
class Implementation extends DerivedAbstractClass {
51+
prop = "";
52+
cb = (s: string) => {};
53+
54+
constructor(str: string, other: AbstractClass, yetAnother: DerivedAbstractClass) {
55+
super(str, other, yetAnother);
56+
this.cb(this.prop);
57+
}
58+
59+
method(n: number) {
60+
this.cb(this.prop + n);
61+
}
62+
}
63+
3464
class User {
3565
constructor(a: AbstractClass) {
3666
a.prop;
@@ -42,6 +72,19 @@ class User {
4272

4373

4474
//// [abstractPropertyInConstructor.js]
75+
var __extends = (this && this.__extends) || (function () {
76+
var extendStatics = function (d, b) {
77+
extendStatics = Object.setPrototypeOf ||
78+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
79+
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
80+
return extendStatics(d, b);
81+
}
82+
return function (d, b) {
83+
extendStatics(d, b);
84+
function __() { this.constructor = d; }
85+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
86+
};
87+
})();
4588
var AbstractClass = /** @class */ (function () {
4689
function AbstractClass(str, other) {
4790
var _this = this;
@@ -65,6 +108,35 @@ var AbstractClass = /** @class */ (function () {
65108
};
66109
return AbstractClass;
67110
}());
111+
var DerivedAbstractClass = /** @class */ (function (_super) {
112+
__extends(DerivedAbstractClass, _super);
113+
function DerivedAbstractClass(str, other, yetAnother) {
114+
var _this = _super.call(this, str, other) || this;
115+
_this.cb = function (s) { };
116+
// there is no implementation of 'prop' in any base class
117+
_this.cb(_this.prop.toLowerCase());
118+
_this.method(1);
119+
// OK, references are to another instance
120+
other.cb(other.prop);
121+
yetAnother.cb(yetAnother.prop);
122+
return _this;
123+
}
124+
return DerivedAbstractClass;
125+
}(AbstractClass));
126+
var Implementation = /** @class */ (function (_super) {
127+
__extends(Implementation, _super);
128+
function Implementation(str, other, yetAnother) {
129+
var _this = _super.call(this, str, other, yetAnother) || this;
130+
_this.prop = "";
131+
_this.cb = function (s) { };
132+
_this.cb(_this.prop);
133+
return _this;
134+
}
135+
Implementation.prototype.method = function (n) {
136+
this.cb(this.prop + n);
137+
};
138+
return Implementation;
139+
}(DerivedAbstractClass));
68140
var User = /** @class */ (function () {
69141
function User(a) {
70142
a.prop;

tests/baselines/reference/abstractPropertyInConstructor.symbols

Lines changed: 109 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -92,31 +92,134 @@ abstract class AbstractClass {
9292
}
9393
}
9494

95+
abstract class DerivedAbstractClass extends AbstractClass {
96+
>DerivedAbstractClass : Symbol(DerivedAbstractClass, Decl(abstractPropertyInConstructor.ts, 30, 1))
97+
>AbstractClass : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0))
98+
99+
cb = (s: string) => {};
100+
>cb : Symbol(DerivedAbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 32, 59))
101+
>s : Symbol(s, Decl(abstractPropertyInConstructor.ts, 33, 10))
102+
103+
constructor(str: string, other: AbstractClass, yetAnother: DerivedAbstractClass) {
104+
>str : Symbol(str, Decl(abstractPropertyInConstructor.ts, 35, 16))
105+
>other : Symbol(other, Decl(abstractPropertyInConstructor.ts, 35, 28))
106+
>AbstractClass : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0))
107+
>yetAnother : Symbol(yetAnother, Decl(abstractPropertyInConstructor.ts, 35, 50))
108+
>DerivedAbstractClass : Symbol(DerivedAbstractClass, Decl(abstractPropertyInConstructor.ts, 30, 1))
109+
110+
super(str, other);
111+
>super : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0))
112+
>str : Symbol(str, Decl(abstractPropertyInConstructor.ts, 35, 16))
113+
>other : Symbol(other, Decl(abstractPropertyInConstructor.ts, 35, 28))
114+
115+
// there is no implementation of 'prop' in any base class
116+
this.cb(this.prop.toLowerCase());
117+
>this.cb : Symbol(DerivedAbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 32, 59))
118+
>this : Symbol(DerivedAbstractClass, Decl(abstractPropertyInConstructor.ts, 30, 1))
119+
>cb : Symbol(DerivedAbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 32, 59))
120+
>this.prop.toLowerCase : Symbol(String.toLowerCase, Decl(lib.es5.d.ts, --, --))
121+
>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
122+
>this : Symbol(DerivedAbstractClass, Decl(abstractPropertyInConstructor.ts, 30, 1))
123+
>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
124+
>toLowerCase : Symbol(String.toLowerCase, Decl(lib.es5.d.ts, --, --))
125+
126+
this.method(1);
127+
>this.method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37))
128+
>this : Symbol(DerivedAbstractClass, Decl(abstractPropertyInConstructor.ts, 30, 1))
129+
>method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37))
130+
131+
// OK, references are to another instance
132+
other.cb(other.prop);
133+
>other.cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26))
134+
>other : Symbol(other, Decl(abstractPropertyInConstructor.ts, 35, 28))
135+
>cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26))
136+
>other.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
137+
>other : Symbol(other, Decl(abstractPropertyInConstructor.ts, 35, 28))
138+
>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
139+
140+
yetAnother.cb(yetAnother.prop);
141+
>yetAnother.cb : Symbol(DerivedAbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 32, 59))
142+
>yetAnother : Symbol(yetAnother, Decl(abstractPropertyInConstructor.ts, 35, 50))
143+
>cb : Symbol(DerivedAbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 32, 59))
144+
>yetAnother.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
145+
>yetAnother : Symbol(yetAnother, Decl(abstractPropertyInConstructor.ts, 35, 50))
146+
>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
147+
}
148+
}
149+
150+
class Implementation extends DerivedAbstractClass {
151+
>Implementation : Symbol(Implementation, Decl(abstractPropertyInConstructor.ts, 46, 1))
152+
>DerivedAbstractClass : Symbol(DerivedAbstractClass, Decl(abstractPropertyInConstructor.ts, 30, 1))
153+
154+
prop = "";
155+
>prop : Symbol(Implementation.prop, Decl(abstractPropertyInConstructor.ts, 48, 51))
156+
157+
cb = (s: string) => {};
158+
>cb : Symbol(Implementation.cb, Decl(abstractPropertyInConstructor.ts, 49, 14))
159+
>s : Symbol(s, Decl(abstractPropertyInConstructor.ts, 50, 10))
160+
161+
constructor(str: string, other: AbstractClass, yetAnother: DerivedAbstractClass) {
162+
>str : Symbol(str, Decl(abstractPropertyInConstructor.ts, 52, 16))
163+
>other : Symbol(other, Decl(abstractPropertyInConstructor.ts, 52, 28))
164+
>AbstractClass : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0))
165+
>yetAnother : Symbol(yetAnother, Decl(abstractPropertyInConstructor.ts, 52, 50))
166+
>DerivedAbstractClass : Symbol(DerivedAbstractClass, Decl(abstractPropertyInConstructor.ts, 30, 1))
167+
168+
super(str, other, yetAnother);
169+
>super : Symbol(DerivedAbstractClass, Decl(abstractPropertyInConstructor.ts, 30, 1))
170+
>str : Symbol(str, Decl(abstractPropertyInConstructor.ts, 52, 16))
171+
>other : Symbol(other, Decl(abstractPropertyInConstructor.ts, 52, 28))
172+
>yetAnother : Symbol(yetAnother, Decl(abstractPropertyInConstructor.ts, 52, 50))
173+
174+
this.cb(this.prop);
175+
>this.cb : Symbol(Implementation.cb, Decl(abstractPropertyInConstructor.ts, 49, 14))
176+
>this : Symbol(Implementation, Decl(abstractPropertyInConstructor.ts, 46, 1))
177+
>cb : Symbol(Implementation.cb, Decl(abstractPropertyInConstructor.ts, 49, 14))
178+
>this.prop : Symbol(Implementation.prop, Decl(abstractPropertyInConstructor.ts, 48, 51))
179+
>this : Symbol(Implementation, Decl(abstractPropertyInConstructor.ts, 46, 1))
180+
>prop : Symbol(Implementation.prop, Decl(abstractPropertyInConstructor.ts, 48, 51))
181+
}
182+
183+
method(n: number) {
184+
>method : Symbol(Implementation.method, Decl(abstractPropertyInConstructor.ts, 55, 5))
185+
>n : Symbol(n, Decl(abstractPropertyInConstructor.ts, 57, 11))
186+
187+
this.cb(this.prop + n);
188+
>this.cb : Symbol(Implementation.cb, Decl(abstractPropertyInConstructor.ts, 49, 14))
189+
>this : Symbol(Implementation, Decl(abstractPropertyInConstructor.ts, 46, 1))
190+
>cb : Symbol(Implementation.cb, Decl(abstractPropertyInConstructor.ts, 49, 14))
191+
>this.prop : Symbol(Implementation.prop, Decl(abstractPropertyInConstructor.ts, 48, 51))
192+
>this : Symbol(Implementation, Decl(abstractPropertyInConstructor.ts, 46, 1))
193+
>prop : Symbol(Implementation.prop, Decl(abstractPropertyInConstructor.ts, 48, 51))
194+
>n : Symbol(n, Decl(abstractPropertyInConstructor.ts, 57, 11))
195+
}
196+
}
197+
95198
class User {
96-
>User : Symbol(User, Decl(abstractPropertyInConstructor.ts, 30, 1))
199+
>User : Symbol(User, Decl(abstractPropertyInConstructor.ts, 60, 1))
97200

98201
constructor(a: AbstractClass) {
99-
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 33, 16))
202+
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 63, 16))
100203
>AbstractClass : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0))
101204

102205
a.prop;
103206
>a.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
104-
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 33, 16))
207+
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 63, 16))
105208
>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
106209

107210
a.cb("hi");
108211
>a.cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26))
109-
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 33, 16))
212+
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 63, 16))
110213
>cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26))
111214

112215
a.method(12);
113216
>a.method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37))
114-
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 33, 16))
217+
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 63, 16))
115218
>method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37))
116219

117220
a.method2();
118221
>a.method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 25, 25))
119-
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 33, 16))
222+
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 63, 16))
120223
>method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 25, 25))
121224
}
122225
}

0 commit comments

Comments
 (0)