Merge pull request #8712 from Microsoft/readonly_assignment_in_constructor

Allow assignment to readonly parameter property within the constructor
This commit is contained in:
Andy
2016-05-23 13:21:22 -07:00
4 changed files with 187 additions and 1 deletions
+7 -1
View File
@@ -11877,8 +11877,14 @@ namespace ts {
if (symbol.flags & SymbolFlags.Property &&
(expr.kind === SyntaxKind.PropertyAccessExpression || expr.kind === SyntaxKind.ElementAccessExpression) &&
(expr as PropertyAccessExpression | ElementAccessExpression).expression.kind === SyntaxKind.ThisKeyword) {
// Look for if this is the constructor for the class that `symbol` is a property of.
const func = getContainingFunction(expr);
return !(func && func.kind === SyntaxKind.Constructor && func.parent === symbol.valueDeclaration.parent);
if (!(func && func.kind === SyntaxKind.Constructor))
return true;
// If func.parent is a class and symbol is a (readonly) property of that class, or
// if func is a constructor and symbol is a (readonly) parameter property declared in it,
// then symbol is writeable here.
return !(func.parent === symbol.valueDeclaration.parent || func === symbol.valueDeclaration.parent);
}
return true;
}
@@ -0,0 +1,50 @@
tests/cases/conformance/classes/constructorDeclarations/constructorParameters/readonlyConstructorAssignment.ts(13,9): error TS2450: Left-hand side of assignment expression cannot be a constant or a read-only property.
tests/cases/conformance/classes/constructorDeclarations/constructorParameters/readonlyConstructorAssignment.ts(33,7): error TS2415: Class 'E' incorrectly extends base class 'D'.
Property 'x' is private in type 'D' but not in type 'E'.
==== tests/cases/conformance/classes/constructorDeclarations/constructorParameters/readonlyConstructorAssignment.ts (2 errors) ====
// Tests that readonly parameter properties behave like regular readonly properties
class A {
constructor(readonly x: number) {
this.x = 0;
}
}
class B extends A {
constructor(x: number) {
super(x);
// Fails, x is readonly
this.x = 1;
~~~~~~
!!! error TS2450: Left-hand side of assignment expression cannot be a constant or a read-only property.
}
}
class C extends A {
// This is the usual behavior of readonly properties:
// if one is redeclared in a base class, then it can be assigned to.
constructor(readonly x: number) {
super(x);
this.x = 1;
}
}
class D {
constructor(private readonly x: number) {
this.x = 0;
}
}
// Fails, can't redeclare readonly property
class E extends D {
~
!!! error TS2415: Class 'E' incorrectly extends base class 'D'.
!!! error TS2415: Property 'x' is private in type 'D' but not in type 'E'.
constructor(readonly x: number) {
super(x);
this.x = 1;
}
}
@@ -0,0 +1,92 @@
//// [readonlyConstructorAssignment.ts]
// Tests that readonly parameter properties behave like regular readonly properties
class A {
constructor(readonly x: number) {
this.x = 0;
}
}
class B extends A {
constructor(x: number) {
super(x);
// Fails, x is readonly
this.x = 1;
}
}
class C extends A {
// This is the usual behavior of readonly properties:
// if one is redeclared in a base class, then it can be assigned to.
constructor(readonly x: number) {
super(x);
this.x = 1;
}
}
class D {
constructor(private readonly x: number) {
this.x = 0;
}
}
// Fails, can't redeclare readonly property
class E extends D {
constructor(readonly x: number) {
super(x);
this.x = 1;
}
}
//// [readonlyConstructorAssignment.js]
// Tests that readonly parameter properties behave like regular readonly properties
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var A = (function () {
function A(x) {
this.x = x;
this.x = 0;
}
return A;
}());
var B = (function (_super) {
__extends(B, _super);
function B(x) {
_super.call(this, x);
// Fails, x is readonly
this.x = 1;
}
return B;
}(A));
var C = (function (_super) {
__extends(C, _super);
// This is the usual behavior of readonly properties:
// if one is redeclared in a base class, then it can be assigned to.
function C(x) {
_super.call(this, x);
this.x = x;
this.x = 1;
}
return C;
}(A));
var D = (function () {
function D(x) {
this.x = x;
this.x = 0;
}
return D;
}());
// Fails, can't redeclare readonly property
var E = (function (_super) {
__extends(E, _super);
function E(x) {
_super.call(this, x);
this.x = x;
this.x = 1;
}
return E;
}(D));
@@ -0,0 +1,38 @@
// Tests that readonly parameter properties behave like regular readonly properties
class A {
constructor(readonly x: number) {
this.x = 0;
}
}
class B extends A {
constructor(x: number) {
super(x);
// Fails, x is readonly
this.x = 1;
}
}
class C extends A {
// This is the usual behavior of readonly properties:
// if one is redeclared in a base class, then it can be assigned to.
constructor(readonly x: number) {
super(x);
this.x = 1;
}
}
class D {
constructor(private readonly x: number) {
this.x = 0;
}
}
// Fails, can't redeclare readonly property
class E extends D {
constructor(readonly x: number) {
super(x);
this.x = 1;
}
}