Fix #7590: Allow 'readonly' to be used in constructor parameters
This commit is contained in:
parent
b68e93966a
commit
ad2634e343
|
@ -12658,7 +12658,7 @@ namespace ts {
|
|||
|
||||
checkVariableLikeDeclaration(node);
|
||||
let func = getContainingFunction(node);
|
||||
if (node.flags & NodeFlags.AccessibilityModifier) {
|
||||
if (node.flags & NodeFlags.ConstructorParameterModifier) {
|
||||
func = getContainingFunction(node);
|
||||
if (!(func.kind === SyntaxKind.Constructor && nodeIsPresent(func.body))) {
|
||||
error(node, Diagnostics.A_parameter_property_is_only_allowed_in_a_constructor_implementation);
|
||||
|
@ -12994,7 +12994,7 @@ namespace ts {
|
|||
// or the containing class declares instance member variables with initializers.
|
||||
const superCallShouldBeFirst =
|
||||
forEach((<ClassDeclaration>node.parent).members, isInstancePropertyWithInitializer) ||
|
||||
forEach(node.parameters, p => p.flags & (NodeFlags.Public | NodeFlags.Private | NodeFlags.Protected));
|
||||
forEach(node.parameters, p => p.flags & NodeFlags.ConstructorParameterModifier);
|
||||
|
||||
// Skip past any prologue directives to find the first statement
|
||||
// to ensure that it was a super call.
|
||||
|
@ -17651,7 +17651,8 @@ namespace ts {
|
|||
if (flags & NodeFlags.Readonly) {
|
||||
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "readonly");
|
||||
}
|
||||
else if (node.kind !== SyntaxKind.PropertyDeclaration && node.kind !== SyntaxKind.PropertySignature && node.kind !== SyntaxKind.IndexSignature) {
|
||||
else if (node.kind !== SyntaxKind.PropertyDeclaration && node.kind !== SyntaxKind.PropertySignature && node.kind !== SyntaxKind.IndexSignature &&
|
||||
!(node.kind == SyntaxKind.Parameter && isParameterPropertyDeclaration(<ParameterDeclaration> node))) {
|
||||
return grammarErrorOnNode(modifier, Diagnostics.readonly_modifier_can_only_appear_on_a_property_declaration_or_index_signature);
|
||||
}
|
||||
flags |= NodeFlags.Readonly;
|
||||
|
@ -17759,7 +17760,7 @@ namespace ts {
|
|||
else if ((node.kind === SyntaxKind.ImportDeclaration || node.kind === SyntaxKind.ImportEqualsDeclaration) && flags & NodeFlags.Ambient) {
|
||||
return grammarErrorOnNode(lastDeclare, Diagnostics.A_0_modifier_cannot_be_used_with_an_import_declaration, "declare");
|
||||
}
|
||||
else if (node.kind === SyntaxKind.Parameter && (flags & NodeFlags.AccessibilityModifier) && isBindingPattern((<ParameterDeclaration>node).name)) {
|
||||
else if (node.kind === SyntaxKind.Parameter && (flags & NodeFlags.ConstructorParameterModifier) && isBindingPattern((<ParameterDeclaration>node).name)) {
|
||||
return grammarErrorOnNode(node, Diagnostics.A_parameter_property_may_not_be_a_binding_pattern);
|
||||
}
|
||||
if (flags & NodeFlags.Async) {
|
||||
|
|
|
@ -1051,7 +1051,7 @@ namespace ts {
|
|||
function emitParameterProperties(constructorDeclaration: ConstructorDeclaration) {
|
||||
if (constructorDeclaration) {
|
||||
forEach(constructorDeclaration.parameters, param => {
|
||||
if (param.flags & NodeFlags.AccessibilityModifier) {
|
||||
if (param.flags & NodeFlags.ConstructorParameterModifier) {
|
||||
emitPropertyDeclaration(param);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -4979,7 +4979,7 @@ const _super = (function (geti, seti) {
|
|||
|
||||
function emitParameterPropertyAssignments(node: ConstructorDeclaration) {
|
||||
forEach(node.parameters, param => {
|
||||
if (param.flags & NodeFlags.AccessibilityModifier) {
|
||||
if (param.flags & NodeFlags.ConstructorParameterModifier) {
|
||||
writeLine();
|
||||
emitStart(param);
|
||||
emitStart(param.name);
|
||||
|
|
|
@ -407,8 +407,10 @@ namespace ts {
|
|||
HasAggregatedChildData = 1 << 29, // If we've computed data from children and cached it in this node
|
||||
HasJsxSpreadAttribute = 1 << 30,
|
||||
|
||||
Modifier = Export | Ambient | Public | Private | Protected | Static | Abstract | Default | Async,
|
||||
Modifier = Export | Ambient | Public | Private | Protected | Static | Abstract | Default | Async | Readonly,
|
||||
AccessibilityModifier = Public | Private | Protected,
|
||||
// Accessibility modifiers and 'readonly' can be attached to a parameter in a constructor to make it a property.
|
||||
ConstructorParameterModifier = AccessibilityModifier | Readonly,
|
||||
BlockScoped = Let | Const,
|
||||
|
||||
ReachabilityCheckFlags = HasImplicitReturn | HasExplicitReturn,
|
||||
|
|
|
@ -3021,7 +3021,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
export function isParameterPropertyDeclaration(node: ParameterDeclaration): boolean {
|
||||
return node.flags & NodeFlags.AccessibilityModifier && node.parent.kind === SyntaxKind.Constructor && isClassLike(node.parent.parent);
|
||||
return node.flags & NodeFlags.ConstructorParameterModifier && node.parent.kind === SyntaxKind.Constructor && isClassLike(node.parent.parent);
|
||||
}
|
||||
|
||||
export function startsWith(str: string, prefix: string): boolean {
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
tests/cases/conformance/classes/constructorDeclarations/constructorParameters/readonlyInAmbientClass.ts(2,14): error TS2369: A parameter property is only allowed in a constructor implementation.
|
||||
|
||||
|
||||
==== tests/cases/conformance/classes/constructorDeclarations/constructorParameters/readonlyInAmbientClass.ts (1 errors) ====
|
||||
declare class C{
|
||||
constructor(readonly x: number);
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2369: A parameter property is only allowed in a constructor implementation.
|
||||
}
|
6
tests/baselines/reference/readonlyInAmbientClass.js
Normal file
6
tests/baselines/reference/readonlyInAmbientClass.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
//// [readonlyInAmbientClass.ts]
|
||||
declare class C{
|
||||
constructor(readonly x: number);
|
||||
}
|
||||
|
||||
//// [readonlyInAmbientClass.js]
|
|
@ -0,0 +1,25 @@
|
|||
tests/cases/conformance/classes/constructorDeclarations/constructorParameters/readonlyInConstructorParameters.ts(4,1): error TS2450: Left-hand side of assignment expression cannot be a constant or a read-only property.
|
||||
tests/cases/conformance/classes/constructorDeclarations/constructorParameters/readonlyInConstructorParameters.ts(7,26): error TS1029: 'public' modifier must precede 'readonly' modifier.
|
||||
tests/cases/conformance/classes/constructorDeclarations/constructorParameters/readonlyInConstructorParameters.ts(13,10): error TS2341: Property 'x' is private and only accessible within class 'F'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/classes/constructorDeclarations/constructorParameters/readonlyInConstructorParameters.ts (3 errors) ====
|
||||
class C {
|
||||
constructor(readonly x: number) {}
|
||||
}
|
||||
new C(1).x = 2;
|
||||
~~~~~~~~~~
|
||||
!!! error TS2450: Left-hand side of assignment expression cannot be a constant or a read-only property.
|
||||
|
||||
class E {
|
||||
constructor(readonly public x: number) {}
|
||||
~~~~~~
|
||||
!!! error TS1029: 'public' modifier must precede 'readonly' modifier.
|
||||
}
|
||||
|
||||
class F {
|
||||
constructor(private readonly x: number) {}
|
||||
}
|
||||
new F(1).x;
|
||||
~
|
||||
!!! error TS2341: Property 'x' is private and only accessible within class 'F'.
|
36
tests/baselines/reference/readonlyInConstructorParameters.js
Normal file
36
tests/baselines/reference/readonlyInConstructorParameters.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
//// [readonlyInConstructorParameters.ts]
|
||||
class C {
|
||||
constructor(readonly x: number) {}
|
||||
}
|
||||
new C(1).x = 2;
|
||||
|
||||
class E {
|
||||
constructor(readonly public x: number) {}
|
||||
}
|
||||
|
||||
class F {
|
||||
constructor(private readonly x: number) {}
|
||||
}
|
||||
new F(1).x;
|
||||
|
||||
//// [readonlyInConstructorParameters.js]
|
||||
var C = (function () {
|
||||
function C(x) {
|
||||
this.x = x;
|
||||
}
|
||||
return C;
|
||||
}());
|
||||
new C(1).x = 2;
|
||||
var E = (function () {
|
||||
function E(x) {
|
||||
this.x = x;
|
||||
}
|
||||
return E;
|
||||
}());
|
||||
var F = (function () {
|
||||
function F(x) {
|
||||
this.x = x;
|
||||
}
|
||||
return F;
|
||||
}());
|
||||
new F(1).x;
|
13
tests/baselines/reference/readonlyReadonly.errors.txt
Normal file
13
tests/baselines/reference/readonlyReadonly.errors.txt
Normal file
|
@ -0,0 +1,13 @@
|
|||
tests/cases/conformance/classes/constructorDeclarations/constructorParameters/readonlyReadonly.ts(2,14): error TS1030: 'readonly' modifier already seen.
|
||||
tests/cases/conformance/classes/constructorDeclarations/constructorParameters/readonlyReadonly.ts(3,26): error TS1030: 'readonly' modifier already seen.
|
||||
|
||||
|
||||
==== tests/cases/conformance/classes/constructorDeclarations/constructorParameters/readonlyReadonly.ts (2 errors) ====
|
||||
class C {
|
||||
readonly readonly x: number;
|
||||
~~~~~~~~
|
||||
!!! error TS1030: 'readonly' modifier already seen.
|
||||
constructor(readonly readonly y: number) {}
|
||||
~~~~~~~~
|
||||
!!! error TS1030: 'readonly' modifier already seen.
|
||||
}
|
13
tests/baselines/reference/readonlyReadonly.js
Normal file
13
tests/baselines/reference/readonlyReadonly.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
//// [readonlyReadonly.ts]
|
||||
class C {
|
||||
readonly readonly x: number;
|
||||
constructor(readonly readonly y: number) {}
|
||||
}
|
||||
|
||||
//// [readonlyReadonly.js]
|
||||
var C = (function () {
|
||||
function C(y) {
|
||||
this.y = y;
|
||||
}
|
||||
return C;
|
||||
}());
|
|
@ -0,0 +1,3 @@
|
|||
declare class C{
|
||||
constructor(readonly x: number);
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
class C {
|
||||
constructor(readonly x: number) {}
|
||||
}
|
||||
new C(1).x = 2;
|
||||
|
||||
class E {
|
||||
constructor(readonly public x: number) {}
|
||||
}
|
||||
|
||||
class F {
|
||||
constructor(private readonly x: number) {}
|
||||
}
|
||||
new F(1).x;
|
|
@ -0,0 +1,4 @@
|
|||
class C {
|
||||
readonly readonly x: number;
|
||||
constructor(readonly readonly y: number) {}
|
||||
}
|
Loading…
Reference in a new issue