From 9e00df590d638cad1266e388385396aea2879cc3 Mon Sep 17 00:00:00 2001 From: Charles Pierce Date: Fri, 6 Oct 2017 19:46:29 -0700 Subject: [PATCH 1/3] Error when accessing abstract property in constructor #9230 --- src/compiler/checker.ts | 28 ++++++++-- src/compiler/diagnosticMessages.json | 4 ++ .../abstractPropertyInConstructor.errors.txt | 25 +++++++++ .../abstractPropertyInConstructor.js | 30 ++++++++++ .../abstractPropertyInConstructor.symbols | 48 ++++++++++++++++ .../abstractPropertyInConstructor.types | 56 +++++++++++++++++++ .../compiler/abstractPropertyInConstructor.ts | 15 +++++ 7 files changed, 201 insertions(+), 5 deletions(-) create mode 100644 tests/baselines/reference/abstractPropertyInConstructor.errors.txt create mode 100644 tests/baselines/reference/abstractPropertyInConstructor.js create mode 100644 tests/baselines/reference/abstractPropertyInConstructor.symbols create mode 100644 tests/baselines/reference/abstractPropertyInConstructor.types create mode 100644 tests/cases/compiler/abstractPropertyInConstructor.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a8e18c432a6..9a483ae50ed 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14826,11 +14826,7 @@ namespace ts { // where this references the constructor function object of a derived class, // a super property access is permitted and must specify a public static member function of the base class. if (languageVersion < ScriptTarget.ES2015) { - const hasNonMethodDeclaration = forEachProperty(prop, p => { - const propKind = getDeclarationKindFromSymbol(p); - return propKind !== SyntaxKind.MethodDeclaration && propKind !== SyntaxKind.MethodSignature; - }); - if (hasNonMethodDeclaration) { + if (symbolHasNonMethodDeclaration(prop)) { error(errorNode, Diagnostics.Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword); return false; } @@ -14845,6 +14841,17 @@ 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 (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; + } + } + // Public properties are otherwise accessible. if (!(flags & ModifierFlags.NonPublicAccessibilityModifier)) { return true; @@ -14896,6 +14903,13 @@ namespace ts { return true; } + function symbolHasNonMethodDeclaration(symbol: Symbol) { + return forEachProperty(symbol, prop => { + const propKind = getDeclarationKindFromSymbol(prop); + return propKind !== SyntaxKind.MethodDeclaration && propKind !== SyntaxKind.MethodSignature; + }); + } + function checkNonNullExpression(node: Expression | QualifiedName) { return checkNonNullType(checkExpression(node), node); } @@ -23139,6 +23153,10 @@ namespace ts { return result; } + function isNodeWithinFunction(node: Node, functionDeclaration: FunctionLike) { + return getContainingFunction(node) === functionDeclaration; + } + function isNodeWithinClass(node: Node, classDeclaration: ClassLikeDeclaration) { return !!forEachEnclosingClass(node, n => n === classDeclaration); } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index f3d6d4fcc47..e2d514ba268 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2220,6 +2220,10 @@ "category": "Error", "code": 2714 }, + "Abstract property '{0}' in class '{1}' cannot be accessed in constructor.": { + "category": "Error", + "code": 2715 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/tests/baselines/reference/abstractPropertyInConstructor.errors.txt b/tests/baselines/reference/abstractPropertyInConstructor.errors.txt new file mode 100644 index 00000000000..7e654b440c6 --- /dev/null +++ b/tests/baselines/reference/abstractPropertyInConstructor.errors.txt @@ -0,0 +1,25 @@ +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 (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 constructor. + this.prop = "Hello World"; + ~~~~ +!!! error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in constructor. + } + + abstract prop: string; + + abstract method(num: number): void; + + method2() { + this.prop = this.prop + "!"; + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/abstractPropertyInConstructor.js b/tests/baselines/reference/abstractPropertyInConstructor.js new file mode 100644 index 00000000000..c6d7de6c037 --- /dev/null +++ b/tests/baselines/reference/abstractPropertyInConstructor.js @@ -0,0 +1,30 @@ +//// [abstractPropertyInConstructor.ts] +abstract class AbstractClass { + constructor(str: string) { + this.method(parseInt(str)); + let val = this.prop.toLowerCase(); + this.prop = "Hello World"; + } + + abstract prop: string; + + abstract method(num: number): void; + + method2() { + this.prop = this.prop + "!"; + } +} + + +//// [abstractPropertyInConstructor.js] +var AbstractClass = /** @class */ (function () { + function AbstractClass(str) { + this.method(parseInt(str)); + var val = this.prop.toLowerCase(); + this.prop = "Hello World"; + } + AbstractClass.prototype.method2 = function () { + this.prop = this.prop + "!"; + }; + return AbstractClass; +}()); diff --git a/tests/baselines/reference/abstractPropertyInConstructor.symbols b/tests/baselines/reference/abstractPropertyInConstructor.symbols new file mode 100644 index 00000000000..7d634f80267 --- /dev/null +++ b/tests/baselines/reference/abstractPropertyInConstructor.symbols @@ -0,0 +1,48 @@ +=== tests/cases/compiler/abstractPropertyInConstructor.ts === +abstract class AbstractClass { +>AbstractClass : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) + + constructor(str: string) { +>str : Symbol(str, Decl(abstractPropertyInConstructor.ts, 1, 16)) + + this.method(parseInt(str)); +>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, 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, 5, 5)) +>this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 5, 5)) +>toLowerCase : Symbol(String.toLowerCase, Decl(lib.d.ts, --, --)) + + 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, 5, 5)) + } + + abstract prop: string; +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 5, 5)) + + abstract method(num: number): void; +>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, 9, 39)) + + this.prop = this.prop + "!"; +>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, 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, 5, 5)) + } +} + diff --git a/tests/baselines/reference/abstractPropertyInConstructor.types b/tests/baselines/reference/abstractPropertyInConstructor.types new file mode 100644 index 00000000000..05f7a7752e6 --- /dev/null +++ b/tests/baselines/reference/abstractPropertyInConstructor.types @@ -0,0 +1,56 @@ +=== tests/cases/compiler/abstractPropertyInConstructor.ts === +abstract class AbstractClass { +>AbstractClass : AbstractClass + + constructor(str: string) { +>str : string + + this.method(parseInt(str)); +>this.method(parseInt(str)) : void +>this.method : (num: number) => void +>this : this +>method : (num: number) => void +>parseInt(str) : number +>parseInt : (s: string, radix?: number) => number +>str : string + + let val = this.prop.toLowerCase(); +>val : string +>this.prop.toLowerCase() : string +>this.prop.toLowerCase : () => string +>this.prop : string +>this : this +>prop : string +>toLowerCase : () => string + + this.prop = "Hello World"; +>this.prop = "Hello World" : "Hello World" +>this.prop : string +>this : this +>prop : string +>"Hello World" : "Hello World" + } + + abstract prop: string; +>prop : string + + abstract method(num: number): void; +>method : (num: number) => void +>num : number + + method2() { +>method2 : () => void + + this.prop = this.prop + "!"; +>this.prop = this.prop + "!" : string +>this.prop : string +>this : this +>prop : string +>this.prop + "!" : string +>this.prop : string +>this : this +>prop : string +>"!" : "!" + } +} + diff --git a/tests/cases/compiler/abstractPropertyInConstructor.ts b/tests/cases/compiler/abstractPropertyInConstructor.ts new file mode 100644 index 00000000000..5376aae9d6f --- /dev/null +++ b/tests/cases/compiler/abstractPropertyInConstructor.ts @@ -0,0 +1,15 @@ +abstract class AbstractClass { + constructor(str: string) { + this.method(parseInt(str)); + let val = this.prop.toLowerCase(); + this.prop = "Hello World"; + } + + abstract prop: string; + + abstract method(num: number): void; + + method2() { + this.prop = this.prop + "!"; + } +} From 79f5d968a120e469dbaf432aaad101a708989a6d Mon Sep 17 00:00:00 2001 From: Charles Pierce Date: Mon, 9 Oct 2017 10:57:08 -0700 Subject: [PATCH 2/3] Use ancestor walk to determine if property access is within constructor #9230 --- src/compiler/checker.ts | 17 ++++-- src/compiler/diagnosticMessages.json | 2 +- .../abstractPropertyInConstructor.errors.txt | 26 +++++++--- .../abstractPropertyInConstructor.js | 20 ++++++- .../abstractPropertyInConstructor.symbols | 52 +++++++++++++------ .../abstractPropertyInConstructor.types | 27 +++++++++- .../compiler/abstractPropertyInConstructor.ts | 11 +++- 7 files changed, 123 insertions(+), 32 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9a483ae50ed..8afee9455cf 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14844,10 +14844,9 @@ 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 (declaringClassConstructor && isNodeWithinFunction(node, declaringClassConstructor)) { - error(errorNode, Diagnostics.Abstract_property_0_in_class_1_cannot_be_accessed_in_constructor, symbolToString(prop), typeToString(getDeclaringClass(prop))); + 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))); return false; } } @@ -23153,8 +23152,16 @@ namespace ts { return result; } - function isNodeWithinFunction(node: Node, functionDeclaration: FunctionLike) { - return getContainingFunction(node) === functionDeclaration; + 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 isNodeWithinClass(node: Node, classDeclaration: ClassLikeDeclaration) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index e2d514ba268..9b220a880b0 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 constructor.": { + "Abstract property '{0}' in class '{1}' cannot be accessed in the constructor.": { "category": "Error", "code": 2715 }, diff --git a/tests/baselines/reference/abstractPropertyInConstructor.errors.txt b/tests/baselines/reference/abstractPropertyInConstructor.errors.txt index 7e654b440c6..461dd713d3b 100644 --- a/tests/baselines/reference/abstractPropertyInConstructor.errors.txt +++ b/tests/baselines/reference/abstractPropertyInConstructor.errors.txt @@ -1,20 +1,32 @@ -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(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 (2 errors) ==== +==== tests/cases/compiler/abstractPropertyInConstructor.ts (3 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 constructor. - this.prop = "Hello World"; - ~~~~ -!!! error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in constructor. +!!! 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; + } } 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 c6d7de6c037..18a2937a191 100644 --- a/tests/baselines/reference/abstractPropertyInConstructor.js +++ b/tests/baselines/reference/abstractPropertyInConstructor.js @@ -3,10 +3,19 @@ abstract class AbstractClass { constructor(str: string) { this.method(parseInt(str)); let val = this.prop.toLowerCase(); - this.prop = "Hello World"; + + if (!str) { + this.prop = "Hello World"; + } + this.cb(str); + + const innerFunction = () => { + return this.prop; + } } abstract prop: string; + abstract cb: (s: string) => void; abstract method(num: number): void; @@ -19,9 +28,16 @@ abstract class AbstractClass { //// [abstractPropertyInConstructor.js] var AbstractClass = /** @class */ (function () { function AbstractClass(str) { + var _this = this; this.method(parseInt(str)); var val = this.prop.toLowerCase(); - this.prop = "Hello World"; + if (!str) { + this.prop = "Hello World"; + } + this.cb(str); + var innerFunction = function () { + return _this.prop; + }; } AbstractClass.prototype.method2 = function () { this.prop = this.prop + "!"; diff --git a/tests/baselines/reference/abstractPropertyInConstructor.symbols b/tests/baselines/reference/abstractPropertyInConstructor.symbols index 7d634f80267..0d542ffb0a8 100644 --- a/tests/baselines/reference/abstractPropertyInConstructor.symbols +++ b/tests/baselines/reference/abstractPropertyInConstructor.symbols @@ -6,43 +6,65 @@ abstract class AbstractClass { >str : Symbol(str, Decl(abstractPropertyInConstructor.ts, 1, 16)) this.method(parseInt(str)); ->this.method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 7, 26)) +>this.method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 16, 37)) >this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) ->method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 7, 26)) +>method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 16, 37)) >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, 5, 5)) +>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, 5, 5)) +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) >toLowerCase : Symbol(String.toLowerCase, Decl(lib.d.ts, --, --)) - this.prop = "Hello World"; ->this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 5, 5)) + 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 : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) ->prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 5, 5)) +>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)) + } } abstract prop: string; ->prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 5, 5)) +>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)) abstract method(num: number): void; ->method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 7, 26)) ->num : Symbol(num, Decl(abstractPropertyInConstructor.ts, 9, 20)) +>method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 16, 37)) +>num : Symbol(num, Decl(abstractPropertyInConstructor.ts, 18, 20)) method2() { ->method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 9, 39)) +>method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 18, 39)) this.prop = this.prop + "!"; ->this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 5, 5)) +>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, 5, 5)) ->this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 5, 5)) +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>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, 5, 5)) +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) } } diff --git a/tests/baselines/reference/abstractPropertyInConstructor.types b/tests/baselines/reference/abstractPropertyInConstructor.types index 05f7a7752e6..0ffb5f1bdfd 100644 --- a/tests/baselines/reference/abstractPropertyInConstructor.types +++ b/tests/baselines/reference/abstractPropertyInConstructor.types @@ -23,17 +23,42 @@ abstract class AbstractClass { >prop : string >toLowerCase : () => string - this.prop = "Hello World"; + if (!str) { +>!str : boolean +>str : string + + 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 5376aae9d6f..457fdb473b1 100644 --- a/tests/cases/compiler/abstractPropertyInConstructor.ts +++ b/tests/cases/compiler/abstractPropertyInConstructor.ts @@ -2,10 +2,19 @@ abstract class AbstractClass { constructor(str: string) { this.method(parseInt(str)); let val = this.prop.toLowerCase(); - this.prop = "Hello World"; + + if (!str) { + this.prop = "Hello World"; + } + this.cb(str); + + const innerFunction = () => { + return this.prop; + } } abstract prop: string; + abstract cb: (s: string) => void; abstract method(num: number): void; From 8486c482371e800fcaa83c655f837f70d8ac02af Mon Sep 17 00:00:00 2001 From: Charles Pierce Date: Mon, 9 Oct 2017 13:01:30 -0700 Subject: [PATCH 3/3] Fix linting error in new function --- src/compiler/checker.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8afee9455cf..26e851eb53d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23156,7 +23156,8 @@ namespace ts { return findAncestor(node, element => { if (isConstructorDeclaration(element) && nodeIsPresent(element.body)) { return true; - } else if (element === classDeclaration || isFunctionLikeDeclaration(element)) { + } + else if (element === classDeclaration || isFunctionLikeDeclaration(element)) { return "quit"; }