diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fb62fd57319..81682ef0122 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14904,9 +14904,10 @@ namespace ts { // Referencing Abstract Properties within Constructors is not allowed if ((flags & ModifierFlags.Abstract) && symbolHasNonMethodDeclaration(prop)) { const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop)); + const declaringClassConstructor = declaringClassDeclaration && findConstructorDeclaration(declaringClassDeclaration); - if (declaringClassDeclaration && isNodeWithinConstructor(node, declaringClassDeclaration)) { - error(errorNode, Diagnostics.Abstract_property_0_in_class_1_cannot_be_accessed_in_the_constructor, symbolToString(prop), typeToString(getDeclaringClass(prop))); + if (declaringClassConstructor && isNodeWithinFunction(node, declaringClassConstructor)) { + error(errorNode, Diagnostics.Abstract_property_0_in_class_1_cannot_be_accessed_in_constructor, symbolToString(prop), typeToString(getDeclaringClass(prop))); return false; } } @@ -23221,16 +23222,8 @@ namespace ts { return result; } - function isNodeWithinConstructor(node: Node, classDeclaration: ClassLikeDeclaration) { - return findAncestor(node, element => { - if (isConstructorDeclaration(element) && nodeIsPresent(element.body)) { - return true; - } else if (element === classDeclaration || isFunctionLikeDeclaration(element)) { - return "quit"; - } - - return false; - }); + function isNodeWithinFunction(node: Node, functionDeclaration: FunctionLike) { + return getContainingFunction(node) === functionDeclaration; } function isNodeWithinClass(node: Node, classDeclaration: ClassLikeDeclaration) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 1db368bb541..5f4a26a86a4 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2220,7 +2220,7 @@ "category": "Error", "code": 2714 }, - "Abstract property '{0}' in class '{1}' cannot be accessed in the constructor.": { + "Abstract property '{0}' in class '{1}' cannot be accessed in constructor.": { "category": "Error", "code": 2715 }, diff --git a/tests/baselines/reference/abstractPropertyInConstructor.errors.txt b/tests/baselines/reference/abstractPropertyInConstructor.errors.txt index 461dd713d3b..7e654b440c6 100644 --- a/tests/baselines/reference/abstractPropertyInConstructor.errors.txt +++ b/tests/baselines/reference/abstractPropertyInConstructor.errors.txt @@ -1,32 +1,20 @@ -tests/cases/compiler/abstractPropertyInConstructor.ts(4,24): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor. -tests/cases/compiler/abstractPropertyInConstructor.ts(7,18): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor. -tests/cases/compiler/abstractPropertyInConstructor.ts(9,14): error TS2715: Abstract property 'cb' in class 'AbstractClass' cannot be accessed in the constructor. +tests/cases/compiler/abstractPropertyInConstructor.ts(4,24): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in constructor. +tests/cases/compiler/abstractPropertyInConstructor.ts(5,14): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in constructor. -==== tests/cases/compiler/abstractPropertyInConstructor.ts (3 errors) ==== +==== tests/cases/compiler/abstractPropertyInConstructor.ts (2 errors) ==== abstract class AbstractClass { constructor(str: string) { this.method(parseInt(str)); let val = this.prop.toLowerCase(); ~~~~ -!!! error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor. - - if (!str) { - this.prop = "Hello World"; - ~~~~ -!!! error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor. - } - this.cb(str); - ~~ -!!! error TS2715: Abstract property 'cb' in class 'AbstractClass' cannot be accessed in the constructor. - - const innerFunction = () => { - return this.prop; - } +!!! error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in constructor. + this.prop = "Hello World"; + ~~~~ +!!! error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in constructor. } abstract prop: string; - abstract cb: (s: string) => void; abstract method(num: number): void; diff --git a/tests/baselines/reference/abstractPropertyInConstructor.js b/tests/baselines/reference/abstractPropertyInConstructor.js index 18a2937a191..c6d7de6c037 100644 --- a/tests/baselines/reference/abstractPropertyInConstructor.js +++ b/tests/baselines/reference/abstractPropertyInConstructor.js @@ -3,19 +3,10 @@ abstract class AbstractClass { constructor(str: string) { this.method(parseInt(str)); let val = this.prop.toLowerCase(); - - if (!str) { - this.prop = "Hello World"; - } - this.cb(str); - - const innerFunction = () => { - return this.prop; - } + this.prop = "Hello World"; } abstract prop: string; - abstract cb: (s: string) => void; abstract method(num: number): void; @@ -28,16 +19,9 @@ abstract class AbstractClass { //// [abstractPropertyInConstructor.js] var AbstractClass = /** @class */ (function () { function AbstractClass(str) { - var _this = this; this.method(parseInt(str)); var val = this.prop.toLowerCase(); - if (!str) { - this.prop = "Hello World"; - } - this.cb(str); - var innerFunction = function () { - return _this.prop; - }; + this.prop = "Hello World"; } AbstractClass.prototype.method2 = function () { this.prop = this.prop + "!"; diff --git a/tests/baselines/reference/abstractPropertyInConstructor.symbols b/tests/baselines/reference/abstractPropertyInConstructor.symbols index 0d542ffb0a8..7d634f80267 100644 --- a/tests/baselines/reference/abstractPropertyInConstructor.symbols +++ b/tests/baselines/reference/abstractPropertyInConstructor.symbols @@ -6,65 +6,43 @@ abstract class AbstractClass { >str : Symbol(str, Decl(abstractPropertyInConstructor.ts, 1, 16)) this.method(parseInt(str)); ->this.method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 16, 37)) +>this.method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 7, 26)) >this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) ->method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 16, 37)) +>method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 7, 26)) >parseInt : Symbol(parseInt, Decl(lib.d.ts, --, --)) >str : Symbol(str, Decl(abstractPropertyInConstructor.ts, 1, 16)) let val = this.prop.toLowerCase(); >val : Symbol(val, Decl(abstractPropertyInConstructor.ts, 3, 11)) >this.prop.toLowerCase : Symbol(String.toLowerCase, Decl(lib.d.ts, --, --)) ->this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 5, 5)) >this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) ->prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 5, 5)) >toLowerCase : Symbol(String.toLowerCase, Decl(lib.d.ts, --, --)) - if (!str) { ->str : Symbol(str, Decl(abstractPropertyInConstructor.ts, 1, 16)) - - this.prop = "Hello World"; ->this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) + this.prop = "Hello World"; +>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 5, 5)) >this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) ->prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) - } - this.cb(str); ->this.cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 15, 26)) ->this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) ->cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 15, 26)) ->str : Symbol(str, Decl(abstractPropertyInConstructor.ts, 1, 16)) - - const innerFunction = () => { ->innerFunction : Symbol(innerFunction, Decl(abstractPropertyInConstructor.ts, 10, 13)) - - return this.prop; ->this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) ->this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) ->prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) - } +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 5, 5)) } abstract prop: string; ->prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) - - abstract cb: (s: string) => void; ->cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 15, 26)) ->s : Symbol(s, Decl(abstractPropertyInConstructor.ts, 16, 18)) +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 5, 5)) abstract method(num: number): void; ->method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 16, 37)) ->num : Symbol(num, Decl(abstractPropertyInConstructor.ts, 18, 20)) +>method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 7, 26)) +>num : Symbol(num, Decl(abstractPropertyInConstructor.ts, 9, 20)) method2() { ->method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 18, 39)) +>method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 9, 39)) this.prop = this.prop + "!"; ->this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 5, 5)) >this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) ->prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) ->this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 5, 5)) +>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 5, 5)) >this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) ->prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 5, 5)) } } diff --git a/tests/baselines/reference/abstractPropertyInConstructor.types b/tests/baselines/reference/abstractPropertyInConstructor.types index 0ffb5f1bdfd..05f7a7752e6 100644 --- a/tests/baselines/reference/abstractPropertyInConstructor.types +++ b/tests/baselines/reference/abstractPropertyInConstructor.types @@ -23,42 +23,17 @@ abstract class AbstractClass { >prop : string >toLowerCase : () => string - if (!str) { ->!str : boolean ->str : string - - this.prop = "Hello World"; + this.prop = "Hello World"; >this.prop = "Hello World" : "Hello World" >this.prop : string >this : this >prop : string >"Hello World" : "Hello World" - } - this.cb(str); ->this.cb(str) : void ->this.cb : (s: string) => void ->this : this ->cb : (s: string) => void ->str : string - - const innerFunction = () => { ->innerFunction : () => string ->() => { return this.prop; } : () => string - - return this.prop; ->this.prop : string ->this : this ->prop : string - } } abstract prop: string; >prop : string - abstract cb: (s: string) => void; ->cb : (s: string) => void ->s : string - abstract method(num: number): void; >method : (num: number) => void >num : number diff --git a/tests/cases/compiler/abstractPropertyInConstructor.ts b/tests/cases/compiler/abstractPropertyInConstructor.ts index 457fdb473b1..5376aae9d6f 100644 --- a/tests/cases/compiler/abstractPropertyInConstructor.ts +++ b/tests/cases/compiler/abstractPropertyInConstructor.ts @@ -2,19 +2,10 @@ abstract class AbstractClass { constructor(str: string) { this.method(parseInt(str)); let val = this.prop.toLowerCase(); - - if (!str) { - this.prop = "Hello World"; - } - this.cb(str); - - const innerFunction = () => { - return this.prop; - } + this.prop = "Hello World"; } abstract prop: string; - abstract cb: (s: string) => void; abstract method(num: number): void;