fix(42265): Error accessing abstract property in constructor via destructuring (#42276)

This commit is contained in:
Oleksandr T 2021-03-10 17:26:50 +02:00 committed by GitHub
parent 2e49e286ae
commit b1f86eca3e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 270 additions and 34 deletions

View file

@ -26443,7 +26443,9 @@ namespace ts {
node: PropertyAccessExpression | QualifiedName | PropertyAccessExpression | VariableDeclaration | ParameterDeclaration | ImportTypeNode | PropertyAssignment | ShorthandPropertyAssignment | BindingElement,
isSuper: boolean, type: Type, prop: Symbol): boolean {
const flags = getDeclarationModifierFlagsFromSymbol(prop);
const errorNode = node.kind === SyntaxKind.QualifiedName ? node.right : node.kind === SyntaxKind.ImportType ? node : node.name;
const errorNode = node.kind === SyntaxKind.QualifiedName ? node.right :
node.kind === SyntaxKind.ImportType ? node :
node.kind === SyntaxKind.BindingElement && node.propertyName ? node.propertyName : node.name;
if (isSuper) {
// TS 1.0 spec (April 2014): 4.8.2
@ -26470,7 +26472,8 @@ namespace ts {
}
// Referencing abstract properties within their own constructors is not allowed
if ((flags & ModifierFlags.Abstract) && isThisProperty(node) && symbolHasNonMethodDeclaration(prop)) {
if ((flags & ModifierFlags.Abstract) && symbolHasNonMethodDeclaration(prop) &&
(isThisProperty(node) || isThisInitializedObjectBindingExpression(node) || isObjectBindingPattern(node.parent) && isThisInitializedDeclaration(node.parent.parent))) {
const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop)!);
if (declaringClassDeclaration && isNodeUsedDuringClassInitialization(node)) {
error(errorNode, Diagnostics.Abstract_property_0_in_class_1_cannot_be_accessed_in_the_constructor, symbolToString(prop), getTextOfIdentifierOrLiteral(declaringClassDeclaration.name!)); // TODO: GH#18217
@ -34698,7 +34701,7 @@ namespace ts {
const property = getPropertyOfType(parentType, nameText);
if (property) {
markPropertyAsReferenced(property, /*nodeForCheckWriteOnly*/ undefined, /*isThisAccess*/ false); // A destructuring is never a write-only reference.
checkPropertyAccessibility(parent, !!parent.initializer && parent.initializer.kind === SyntaxKind.SuperKeyword, parentType, property);
checkPropertyAccessibility(node, !!parent.initializer && parent.initializer.kind === SyntaxKind.SuperKeyword, parentType, property);
}
}
}

View file

@ -1731,6 +1731,14 @@ namespace ts {
return !!node && isVariableDeclaration(node) && node.initializer?.kind === SyntaxKind.ThisKeyword;
}
export function isThisInitializedObjectBindingExpression(node: Node | undefined): boolean {
return !!node
&& (isShorthandPropertyAssignment(node) || isPropertyAssignment(node))
&& isBinaryExpression(node.parent.parent)
&& node.parent.parent.operatorToken.kind === SyntaxKind.EqualsToken
&& node.parent.parent.right.kind === SyntaxKind.ThisKeyword;
}
export function getEntityNameFromTypeNode(node: TypeNode): EntityNameOrEntityNameExpression | undefined {
switch (node.kind) {
case SyntaxKind.TypeReference:

View file

@ -4,9 +4,14 @@ tests/cases/compiler/abstractPropertyInConstructor.ts(9,14): error TS2715: Abstr
tests/cases/compiler/abstractPropertyInConstructor.ts(25,18): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
tests/cases/compiler/abstractPropertyInConstructor.ts(25,18): error TS2729: Property 'prop' is used before its initialization.
tests/cases/compiler/abstractPropertyInConstructor.ts(39,22): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
tests/cases/compiler/abstractPropertyInConstructor.ts(78,15): error TS2715: Abstract property 'x' in class 'C1' cannot be accessed in the constructor.
tests/cases/compiler/abstractPropertyInConstructor.ts(78,18): error TS2715: Abstract property 'y' in class 'C1' cannot be accessed in the constructor.
tests/cases/compiler/abstractPropertyInConstructor.ts(79,12): error TS2715: Abstract property 'x' in class 'C1' cannot be accessed in the constructor.
tests/cases/compiler/abstractPropertyInConstructor.ts(79,15): error TS2715: Abstract property 'y' in class 'C1' cannot be accessed in the constructor.
tests/cases/compiler/abstractPropertyInConstructor.ts(79,22): error TS2715: Abstract property 'y' in class 'C1' cannot be accessed in the constructor.
==== tests/cases/compiler/abstractPropertyInConstructor.ts (6 errors) ====
==== tests/cases/compiler/abstractPropertyInConstructor.ts (11 errors) ====
abstract class AbstractClass {
constructor(str: string, other: AbstractClass) {
this.method(parseInt(str));
@ -90,4 +95,36 @@ tests/cases/compiler/abstractPropertyInConstructor.ts(39,22): error TS2715: Abst
a.method2();
}
}
abstract class C1 {
abstract x: string;
abstract y: string;
constructor() {
let self = this; // ok
let { x, y: y1 } = this; // error
~
!!! error TS2715: Abstract property 'x' in class 'C1' cannot be accessed in the constructor.
~
!!! error TS2715: Abstract property 'y' in class 'C1' cannot be accessed in the constructor.
({ x, y: y1, "y": y1 } = this); // error
~
!!! error TS2715: Abstract property 'x' in class 'C1' cannot be accessed in the constructor.
~
!!! error TS2715: Abstract property 'y' in class 'C1' cannot be accessed in the constructor.
~~~
!!! error TS2715: Abstract property 'y' in class 'C1' cannot be accessed in the constructor.
}
}
class C2 {
x: string;
y: string;
constructor() {
let self = this; // ok
let { x, y: y1 } = this; // ok
({ x, y: y1, "y": y1 } = this); // ok
}
}

View file

@ -69,6 +69,28 @@ class User {
a.method2();
}
}
abstract class C1 {
abstract x: string;
abstract y: string;
constructor() {
let self = this; // ok
let { x, y: y1 } = this; // error
({ x, y: y1, "y": y1 } = this); // error
}
}
class C2 {
x: string;
y: string;
constructor() {
let self = this; // ok
let { x, y: y1 } = this; // ok
({ x, y: y1, "y": y1 } = this); // ok
}
}
//// [abstractPropertyInConstructor.js]
@ -148,3 +170,21 @@ var User = /** @class */ (function () {
}
return User;
}());
var C1 = /** @class */ (function () {
function C1() {
var _a;
var self = this; // ok
var _b = this, x = _b.x, y1 = _b.y; // error
(_a = this, x = _a.x, y1 = _a.y, y1 = _a["y"]); // error
}
return C1;
}());
var C2 = /** @class */ (function () {
function C2() {
var _a;
var self = this; // ok
var _b = this, x = _b.x, y1 = _b.y; // ok
(_a = this, x = _a.x, y1 = _a.y, y1 = _a["y"]); // ok
}
return C2;
}());

View file

@ -224,3 +224,63 @@ class User {
}
}
abstract class C1 {
>C1 : Symbol(C1, Decl(abstractPropertyInConstructor.ts, 69, 1))
abstract x: string;
>x : Symbol(C1.x, Decl(abstractPropertyInConstructor.ts, 71, 19))
abstract y: string;
>y : Symbol(C1.y, Decl(abstractPropertyInConstructor.ts, 72, 23))
constructor() {
let self = this; // ok
>self : Symbol(self, Decl(abstractPropertyInConstructor.ts, 76, 11))
>this : Symbol(C1, Decl(abstractPropertyInConstructor.ts, 69, 1))
let { x, y: y1 } = this; // error
>x : Symbol(x, Decl(abstractPropertyInConstructor.ts, 77, 13))
>y : Symbol(C1.y, Decl(abstractPropertyInConstructor.ts, 72, 23))
>y1 : Symbol(y1, Decl(abstractPropertyInConstructor.ts, 77, 16))
>this : Symbol(C1, Decl(abstractPropertyInConstructor.ts, 69, 1))
({ x, y: y1, "y": y1 } = this); // error
>x : Symbol(x, Decl(abstractPropertyInConstructor.ts, 78, 10))
>y : Symbol(y, Decl(abstractPropertyInConstructor.ts, 78, 13), Decl(abstractPropertyInConstructor.ts, 78, 20))
>y1 : Symbol(y1, Decl(abstractPropertyInConstructor.ts, 77, 16))
>"y" : Symbol(y, Decl(abstractPropertyInConstructor.ts, 78, 13), Decl(abstractPropertyInConstructor.ts, 78, 20))
>y1 : Symbol(y1, Decl(abstractPropertyInConstructor.ts, 77, 16))
>this : Symbol(C1, Decl(abstractPropertyInConstructor.ts, 69, 1))
}
}
class C2 {
>C2 : Symbol(C2, Decl(abstractPropertyInConstructor.ts, 80, 1))
x: string;
>x : Symbol(C2.x, Decl(abstractPropertyInConstructor.ts, 82, 10))
y: string;
>y : Symbol(C2.y, Decl(abstractPropertyInConstructor.ts, 83, 14))
constructor() {
let self = this; // ok
>self : Symbol(self, Decl(abstractPropertyInConstructor.ts, 87, 11))
>this : Symbol(C2, Decl(abstractPropertyInConstructor.ts, 80, 1))
let { x, y: y1 } = this; // ok
>x : Symbol(x, Decl(abstractPropertyInConstructor.ts, 88, 13))
>y : Symbol(C2.y, Decl(abstractPropertyInConstructor.ts, 83, 14))
>y1 : Symbol(y1, Decl(abstractPropertyInConstructor.ts, 88, 16))
>this : Symbol(C2, Decl(abstractPropertyInConstructor.ts, 80, 1))
({ x, y: y1, "y": y1 } = this); // ok
>x : Symbol(x, Decl(abstractPropertyInConstructor.ts, 89, 10))
>y : Symbol(y, Decl(abstractPropertyInConstructor.ts, 89, 13), Decl(abstractPropertyInConstructor.ts, 89, 20))
>y1 : Symbol(y1, Decl(abstractPropertyInConstructor.ts, 88, 16))
>"y" : Symbol(y, Decl(abstractPropertyInConstructor.ts, 89, 13), Decl(abstractPropertyInConstructor.ts, 89, 20))
>y1 : Symbol(y1, Decl(abstractPropertyInConstructor.ts, 88, 16))
>this : Symbol(C2, Decl(abstractPropertyInConstructor.ts, 80, 1))
}
}

View file

@ -250,3 +250,69 @@ class User {
}
}
abstract class C1 {
>C1 : C1
abstract x: string;
>x : string
abstract y: string;
>y : string
constructor() {
let self = this; // ok
>self : this
>this : this
let { x, y: y1 } = this; // error
>x : string
>y : any
>y1 : string
>this : this
({ x, y: y1, "y": y1 } = this); // error
>({ x, y: y1, "y": y1 } = this) : this
>{ x, y: y1, "y": y1 } = this : this
>{ x, y: y1, "y": y1 } : { x: string; y: string; }
>x : string
>y : string
>y1 : string
>"y" : string
>y1 : string
>this : this
}
}
class C2 {
>C2 : C2
x: string;
>x : string
y: string;
>y : string
constructor() {
let self = this; // ok
>self : this
>this : this
let { x, y: y1 } = this; // ok
>x : string
>y : any
>y1 : string
>this : this
({ x, y: y1, "y": y1 } = this); // ok
>({ x, y: y1, "y": y1 } = this) : this
>{ x, y: y1, "y": y1 } = this : this
>{ x, y: y1, "y": y1 } : { x: string; y: string; }
>x : string
>y : string
>y1 : string
>"y" : string
>y1 : string
>this : this
}
}

View file

@ -1,7 +1,7 @@
tests/cases/compiler/destructureComputedProperty.ts(7,7): error TS2341: Property 'p' is private and only accessible within class 'C'.
tests/cases/compiler/destructureComputedProperty.ts(8,7): error TS2341: Property 'p' is private and only accessible within class 'C'.
tests/cases/compiler/destructureComputedProperty.ts(9,7): error TS2341: Property 'p' is private and only accessible within class 'C'.
tests/cases/compiler/destructureComputedProperty.ts(10,7): error TS2341: Property 'p' is private and only accessible within class 'C'.
tests/cases/compiler/destructureComputedProperty.ts(7,9): error TS2341: Property 'p' is private and only accessible within class 'C'.
tests/cases/compiler/destructureComputedProperty.ts(8,9): error TS2341: Property 'p' is private and only accessible within class 'C'.
tests/cases/compiler/destructureComputedProperty.ts(9,9): error TS2341: Property 'p' is private and only accessible within class 'C'.
tests/cases/compiler/destructureComputedProperty.ts(10,9): error TS2341: Property 'p' is private and only accessible within class 'C'.
==== tests/cases/compiler/destructureComputedProperty.ts (4 errors) ====
@ -12,15 +12,15 @@ tests/cases/compiler/destructureComputedProperty.ts(10,7): error TS2341: Propert
class C { private p: number; }
const nameP = "p";
const { "p": p0 } = new C();
~~~~~~~~~~~
~~~
!!! error TS2341: Property 'p' is private and only accessible within class 'C'.
const { ["p"]: p1 } = new C();
~~~~~~~~~~~~~
~~~~~
!!! error TS2341: Property 'p' is private and only accessible within class 'C'.
const { [nameP]: p2 } = new C();
~~~~~~~~~~~~~~~
~~~~~~~
!!! error TS2341: Property 'p' is private and only accessible within class 'C'.
const { p: p3 } = new C();
~~~~~~~~~
~
!!! error TS2341: Property 'p' is private and only accessible within class 'C'.

View file

@ -1,13 +1,13 @@
tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(12,13): error TS2341: Property 'priv' is private and only accessible within class 'K'.
tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(17,5): error TS2341: Property 'priv' is private and only accessible within class 'K'.
tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(18,5): error TS2445: Property 'prot' is protected and only accessible within class 'K' and its subclasses.
tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(19,5): error TS2341: Property 'privateMethod' is private and only accessible within class 'K'.
tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(20,5): error TS2341: Property 'priv' is private and only accessible within class 'K'.
tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(20,5): error TS2341: Property 'privateMethod' is private and only accessible within class 'K'.
tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(20,5): error TS2445: Property 'prot' is protected and only accessible within class 'K' and its subclasses.
tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(21,12): error TS2341: Property 'priv' is private and only accessible within class 'K'.
tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(21,12): error TS2341: Property 'privateMethod' is private and only accessible within class 'K'.
tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(21,12): error TS2445: Property 'prot' is protected and only accessible within class 'K' and its subclasses.
tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(12,15): error TS2341: Property 'priv' is private and only accessible within class 'K'.
tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(17,7): error TS2341: Property 'priv' is private and only accessible within class 'K'.
tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(18,7): error TS2445: Property 'prot' is protected and only accessible within class 'K' and its subclasses.
tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(19,7): error TS2341: Property 'privateMethod' is private and only accessible within class 'K'.
tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(20,7): error TS2341: Property 'priv' is private and only accessible within class 'K'.
tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(20,16): error TS2445: Property 'prot' is protected and only accessible within class 'K' and its subclasses.
tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(20,25): error TS2341: Property 'privateMethod' is private and only accessible within class 'K'.
tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(21,14): error TS2341: Property 'priv' is private and only accessible within class 'K'.
tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(21,20): error TS2445: Property 'prot' is protected and only accessible within class 'K' and its subclasses.
tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts(21,26): error TS2341: Property 'privateMethod' is private and only accessible within class 'K'.
==== tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAreNotAccessibleDestructuring.ts (10 errors) ====
@ -23,35 +23,35 @@ tests/cases/conformance/classes/members/accessibility/privateProtectedMembersAre
class C extends K {
m2() {
let { priv: a } = this; // error
~~~~~~~~~~~
~~~~
!!! error TS2341: Property 'priv' is private and only accessible within class 'K'.
let { prot: b } = this; // ok
}
}
let k = new K();
let { priv } = k; // error
~~~~~~~~
~~~~
!!! error TS2341: Property 'priv' is private and only accessible within class 'K'.
let { prot } = k; // error
~~~~~~~~
~~~~
!!! error TS2445: Property 'prot' is protected and only accessible within class 'K' and its subclasses.
let { privateMethod } = k; // error
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~
!!! error TS2341: Property 'privateMethod' is private and only accessible within class 'K'.
let { priv: a, prot: b, privateMethod: pm } = k; // error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~
!!! error TS2341: Property 'priv' is private and only accessible within class 'K'.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2341: Property 'privateMethod' is private and only accessible within class 'K'.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~
!!! error TS2445: Property 'prot' is protected and only accessible within class 'K' and its subclasses.
~~~~~~~~~~~~~
!!! error TS2341: Property 'privateMethod' is private and only accessible within class 'K'.
function f({ priv, prot, privateMethod }: K) {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~
!!! error TS2341: Property 'priv' is private and only accessible within class 'K'.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2341: Property 'privateMethod' is private and only accessible within class 'K'.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~
!!! error TS2445: Property 'prot' is protected and only accessible within class 'K' and its subclasses.
~~~~~~~~~~~~~
!!! error TS2341: Property 'privateMethod' is private and only accessible within class 'K'.
}

View file

@ -68,3 +68,25 @@ class User {
a.method2();
}
}
abstract class C1 {
abstract x: string;
abstract y: string;
constructor() {
let self = this; // ok
let { x, y: y1 } = this; // error
({ x, y: y1, "y": y1 } = this); // error
}
}
class C2 {
x: string;
y: string;
constructor() {
let self = this; // ok
let { x, y: y1 } = this; // ok
({ x, y: y1, "y": y1 } = this); // ok
}
}