Abstract property access error only on this access

This commit is contained in:
Nathan Shively-Sanders 2017-10-16 09:43:49 -07:00
parent fb45b49afc
commit 49beac919c
7 changed files with 93 additions and 44 deletions

View file

@ -14907,7 +14907,7 @@ namespace ts {
}
// Referencing abstract properties within their own constructors is not allowed
if ((flags & ModifierFlags.Abstract) && symbolHasNonMethodDeclaration(prop)) {
if ((flags & ModifierFlags.Abstract) && isThisProperty(node) && symbolHasNonMethodDeclaration(prop)) {
const declaringClassDeclaration = <ClassLikeDeclaration>getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop));
if (declaringClassDeclaration && isNodeWithinConstructorOfClass(node, declaringClassDeclaration)) {
error(errorNode, Diagnostics.Abstract_property_0_in_class_1_cannot_be_accessed_in_the_constructor, symbolToString(prop), getTextOfIdentifierOrLiteral(declaringClassDeclaration.name));

View file

@ -1121,7 +1121,7 @@ namespace ts {
}
/**
* Determines whether a node is a property or element access expression for super.
* Determines whether a node is a property or element access expression for `super`.
*/
export function isSuperProperty(node: Node): node is SuperProperty {
const kind = node.kind;
@ -1129,7 +1129,16 @@ namespace ts {
&& (<PropertyAccessExpression | ElementAccessExpression>node).expression.kind === SyntaxKind.SuperKeyword;
}
export function getEntityNameFromTypeNode(node: TypeNode): EntityNameOrEntityNameExpression {
/**
* Determines whether a node is a property or element access expression for `this`.
*/
export function isThisProperty(node: Node): boolean {
const kind = node.kind;
return (kind === SyntaxKind.PropertyAccessExpression || kind === SyntaxKind.ElementAccessExpression)
&& (<PropertyAccessExpression | ElementAccessExpression>node).expression.kind === SyntaxKind.ThisKeyword;
}
export function getEntityNameFromTypeNode(node: TypeNode): EntityNameOrEntityNameExpression {
switch (node.kind) {
case SyntaxKind.TypeReference:
return (<TypeReferenceNode>node).typeName;

View file

@ -5,7 +5,7 @@ tests/cases/compiler/abstractPropertyInConstructor.ts(9,14): error TS2715: Abstr
==== tests/cases/compiler/abstractPropertyInConstructor.ts (3 errors) ====
abstract class AbstractClass {
constructor(str: string) {
constructor(str: string, other: AbstractClass) {
this.method(parseInt(str));
let val = this.prop.toLowerCase();
~~~~
@ -20,9 +20,13 @@ tests/cases/compiler/abstractPropertyInConstructor.ts(9,14): error TS2715: Abstr
~~
!!! error TS2715: Abstract property 'cb' in class 'AbstractClass' cannot be accessed in the constructor.
// OK, reference is inside function
const innerFunction = () => {
return this.prop;
}
// OK, references are to another instance
other.cb(other.prop);
}
abstract prop: string;

View file

@ -1,6 +1,6 @@
//// [abstractPropertyInConstructor.ts]
abstract class AbstractClass {
constructor(str: string) {
constructor(str: string, other: AbstractClass) {
this.method(parseInt(str));
let val = this.prop.toLowerCase();
@ -9,9 +9,13 @@ abstract class AbstractClass {
}
this.cb(str);
// OK, reference is inside function
const innerFunction = () => {
return this.prop;
}
// OK, references are to another instance
other.cb(other.prop);
}
abstract prop: string;
@ -36,7 +40,7 @@ class User {
//// [abstractPropertyInConstructor.js]
var AbstractClass = /** @class */ (function () {
function AbstractClass(str) {
function AbstractClass(str, other) {
var _this = this;
this.method(parseInt(str));
var val = this.prop.toLowerCase();
@ -44,9 +48,12 @@ var AbstractClass = /** @class */ (function () {
this.prop = "Hello World";
}
this.cb(str);
// OK, reference is inside function
var innerFunction = function () {
return _this.prop;
};
// OK, references are to another instance
other.cb(other.prop);
}
AbstractClass.prototype.method2 = function () {
this.prop = this.prop + "!";

View file

@ -2,98 +2,110 @@
abstract class AbstractClass {
>AbstractClass : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0))
constructor(str: string) {
constructor(str: string, other: AbstractClass) {
>str : Symbol(str, Decl(abstractPropertyInConstructor.ts, 1, 16))
>other : Symbol(other, Decl(abstractPropertyInConstructor.ts, 1, 28))
>AbstractClass : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0))
this.method(parseInt(str));
>this.method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 16, 37))
>this.method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37))
>this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0))
>method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 16, 37))
>method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 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, 13, 5))
>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 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, 17, 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 : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 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, 17, 5))
}
this.cb(str);
>this.cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 15, 26))
>this.cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26))
>this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0))
>cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 15, 26))
>cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26))
>str : Symbol(str, Decl(abstractPropertyInConstructor.ts, 1, 16))
// OK, reference is inside function
const innerFunction = () => {
>innerFunction : Symbol(innerFunction, Decl(abstractPropertyInConstructor.ts, 10, 13))
>innerFunction : Symbol(innerFunction, Decl(abstractPropertyInConstructor.ts, 11, 13))
return this.prop;
>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5))
>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 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, 17, 5))
}
// OK, references are to another instance
other.cb(other.prop);
>other.cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26))
>other : Symbol(other, Decl(abstractPropertyInConstructor.ts, 1, 28))
>cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26))
>other.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
>other : Symbol(other, Decl(abstractPropertyInConstructor.ts, 1, 28))
>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
}
abstract prop: string;
>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5))
>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
abstract cb: (s: string) => void;
>cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 15, 26))
>s : Symbol(s, Decl(abstractPropertyInConstructor.ts, 16, 18))
>cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26))
>s : Symbol(s, Decl(abstractPropertyInConstructor.ts, 20, 18))
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, 20, 37))
>num : Symbol(num, Decl(abstractPropertyInConstructor.ts, 22, 20))
method2() {
>method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 18, 39))
>method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 22, 39))
this.prop = this.prop + "!";
>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5))
>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 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, 17, 5))
>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 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, 17, 5))
}
}
class User {
>User : Symbol(User, Decl(abstractPropertyInConstructor.ts, 23, 1))
>User : Symbol(User, Decl(abstractPropertyInConstructor.ts, 27, 1))
constructor(a: AbstractClass) {
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 26, 16))
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 30, 16))
>AbstractClass : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0))
a.prop;
>a.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5))
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 26, 16))
>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5))
>a.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 30, 16))
>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
a.cb("hi");
>a.cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 15, 26))
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 26, 16))
>cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 15, 26))
>a.cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26))
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 30, 16))
>cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26))
a.method(12);
>a.method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 16, 37))
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 26, 16))
>method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 16, 37))
>a.method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37))
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 30, 16))
>method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37))
a.method2();
>a.method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 18, 39))
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 26, 16))
>method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 18, 39))
>a.method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 22, 39))
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 30, 16))
>method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 22, 39))
}
}

View file

@ -2,8 +2,10 @@
abstract class AbstractClass {
>AbstractClass : AbstractClass
constructor(str: string) {
constructor(str: string, other: AbstractClass) {
>str : string
>other : AbstractClass
>AbstractClass : AbstractClass
this.method(parseInt(str));
>this.method(parseInt(str)) : void
@ -41,6 +43,7 @@ abstract class AbstractClass {
>cb : (s: string) => void
>str : string
// OK, reference is inside function
const innerFunction = () => {
>innerFunction : () => string
>() => { return this.prop; } : () => string
@ -50,6 +53,16 @@ abstract class AbstractClass {
>this : this
>prop : string
}
// OK, references are to another instance
other.cb(other.prop);
>other.cb(other.prop) : void
>other.cb : (s: string) => void
>other : AbstractClass
>cb : (s: string) => void
>other.prop : string
>other : AbstractClass
>prop : string
}
abstract prop: string;

View file

@ -1,5 +1,5 @@
abstract class AbstractClass {
constructor(str: string) {
constructor(str: string, other: AbstractClass) {
this.method(parseInt(str));
let val = this.prop.toLowerCase();
@ -8,9 +8,13 @@ abstract class AbstractClass {
}
this.cb(str);
// OK, reference is inside function
const innerFunction = () => {
return this.prop;
}
// OK, references are to another instance
other.cb(other.prop);
}
abstract prop: string;