Skip to content

Commit 8dd81ea

Browse files
Merge pull request #1673 from Microsoft/unDestructuringParameterProperties
Disallow destructured parameter properties
2 parents 713e545 + e19ebc6 commit 8dd81ea

19 files changed

+713
-5
lines changed

src/compiler/checker.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7206,7 +7206,7 @@ module ts {
72067206

72077207
checkVariableLikeDeclaration(node);
72087208
var func = getContainingFunction(node);
7209-
if (node.flags & (NodeFlags.Public | NodeFlags.Private | NodeFlags.Protected)) {
7209+
if (node.flags & NodeFlags.AccessibilityModifier) {
72107210
func = getContainingFunction(node);
72117211
if (!(func.kind === SyntaxKind.Constructor && nodeIsPresent(func.body))) {
72127212
error(node, Diagnostics.A_parameter_property_is_only_allowed_in_a_constructor_implementation);
@@ -7225,17 +7225,20 @@ module ts {
72257225
checkGrammarIndexSignature(<SignatureDeclaration>node);
72267226
}
72277227
// TODO (yuisu): Remove this check in else-if when SyntaxKind.Construct is moved and ambient context is handled
7228-
else if (node.kind === SyntaxKind.FunctionType || node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.ConstructorType ||
7228+
else if (node.kind === SyntaxKind.FunctionType || node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.ConstructorType ||
72297229
node.kind === SyntaxKind.CallSignature || node.kind === SyntaxKind.Constructor ||
72307230
node.kind === SyntaxKind.ConstructSignature){
72317231
checkGrammarFunctionLikeDeclaration(<FunctionLikeDeclaration>node);
72327232
}
72337233

72347234
checkTypeParameters(node.typeParameters);
7235+
72357236
forEach(node.parameters, checkParameter);
7237+
72367238
if (node.type) {
72377239
checkSourceElement(node.type);
72387240
}
7241+
72397242
if (produceDiagnostics) {
72407243
checkCollisionWithArgumentsInGeneratedCode(node);
72417244
if (compilerOptions.noImplicitAny && !node.type) {
@@ -10186,6 +10189,9 @@ module ts {
1018610189
else if (node.kind === SyntaxKind.InterfaceDeclaration && flags & NodeFlags.Ambient) {
1018710190
return grammarErrorOnNode(lastDeclare, Diagnostics.A_declare_modifier_cannot_be_used_with_an_interface_declaration, "declare");
1018810191
}
10192+
else if (node.kind === SyntaxKind.Parameter && (flags & NodeFlags.AccessibilityModifier) && isBindingPattern((<ParameterDeclaration>node).name)) {
10193+
return grammarErrorOnNode(node, Diagnostics.A_parameter_property_may_not_be_a_binding_pattern);
10194+
}
1018910195
}
1019010196

1019110197
function checkGrammarForDisallowedTrailingComma(list: NodeArray<Node>): boolean {

src/compiler/diagnosticInformationMap.generated.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ module ts {
146146
Modifiers_cannot_appear_here: { code: 1184, category: DiagnosticCategory.Error, key: "Modifiers cannot appear here." },
147147
Merge_conflict_marker_encountered: { code: 1185, category: DiagnosticCategory.Error, key: "Merge conflict marker encountered." },
148148
A_rest_element_cannot_have_an_initializer: { code: 1186, category: DiagnosticCategory.Error, key: "A rest element cannot have an initializer." },
149+
A_parameter_property_may_not_be_a_binding_pattern: { code: 1187, category: DiagnosticCategory.Error, key: "A parameter property may not be a binding pattern." },
149150
Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." },
150151
Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." },
151152
Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." },

src/compiler/diagnosticMessages.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@
224224
"A 'declare' modifier cannot be used with an import declaration.": {
225225
"category": "Error",
226226
"code": 1079,
227-
"isEarly": true
227+
"isEarly": true
228228
},
229229
"Invalid 'reference' directive syntax.": {
230230
"category": "Error",
@@ -659,7 +659,7 @@
659659
"An implementation cannot be declared in ambient contexts.": {
660660
"category": "Error",
661661
"code": 1184,
662-
"isEarly": true
662+
"isEarly": true
663663
},
664664
"Modifiers cannot appear here.": {
665665
"category": "Error",
@@ -673,6 +673,10 @@
673673
"category": "Error",
674674
"code": 1186
675675
},
676+
"A parameter property may not be a binding pattern.": {
677+
"category": "Error",
678+
"code": 1187
679+
},
676680

677681
"Duplicate identifier '{0}'.": {
678682
"category": "Error",

src/compiler/parser.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1395,7 +1395,10 @@ module ts {
13951395
}
13961396

13971397
function canFollowModifier(): boolean {
1398-
return token === SyntaxKind.OpenBracketToken || token === SyntaxKind.AsteriskToken || isLiteralPropertyName();
1398+
return token === SyntaxKind.OpenBracketToken
1399+
|| token === SyntaxKind.OpenBraceToken
1400+
|| token === SyntaxKind.AsteriskToken
1401+
|| isLiteralPropertyName();
13991402
}
14001403

14011404
// True if positioned at the start of a list element
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties1.ts(2,17): error TS1187: A parameter property may not be a binding pattern.
2+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties1.ts(9,17): error TS1187: A parameter property may not be a binding pattern.
3+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties1.ts(16,17): error TS1187: A parameter property may not be a binding pattern.
4+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties1.ts(22,26): error TS2339: Property 'x' does not exist on type 'C1'.
5+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties1.ts(22,35): error TS2339: Property 'y' does not exist on type 'C1'.
6+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties1.ts(22,43): error TS2339: Property 'y' does not exist on type 'C1'.
7+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties1.ts(22,52): error TS2339: Property 'z' does not exist on type 'C1'.
8+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties1.ts(25,30): error TS2339: Property 'x' does not exist on type 'C2'.
9+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties1.ts(25,36): error TS2339: Property 'y' does not exist on type 'C2'.
10+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties1.ts(25,42): error TS2339: Property 'z' does not exist on type 'C2'.
11+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties1.ts(29,30): error TS2339: Property 'x' does not exist on type 'C3'.
12+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties1.ts(29,36): error TS2339: Property 'y' does not exist on type 'C3'.
13+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties1.ts(29,42): error TS2339: Property 'z' does not exist on type 'C3'.
14+
15+
16+
==== tests/cases/conformance/es6/destructuring/destructuringParameterProperties1.ts (13 errors) ====
17+
class C1 {
18+
constructor(public [x, y, z]: string[]) {
19+
~~~~~~~~~~~~~~~~~~~~~~~~~~
20+
!!! error TS1187: A parameter property may not be a binding pattern.
21+
}
22+
}
23+
24+
type TupleType1 = [string, number, boolean];
25+
26+
class C2 {
27+
constructor(public [x, y, z]: TupleType1) {
28+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
29+
!!! error TS1187: A parameter property may not be a binding pattern.
30+
}
31+
}
32+
33+
type ObjType1 = { x: number; y: string; z: boolean }
34+
35+
class C3 {
36+
constructor(public { x, y, z }: ObjType1) {
37+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
38+
!!! error TS1187: A parameter property may not be a binding pattern.
39+
}
40+
}
41+
42+
var c1 = new C1([]);
43+
c1 = new C1(["larry", "{curly}", "moe"]);
44+
var useC1Properties = c1.x === c1.y && c1.y === c1.z;
45+
~
46+
!!! error TS2339: Property 'x' does not exist on type 'C1'.
47+
~
48+
!!! error TS2339: Property 'y' does not exist on type 'C1'.
49+
~
50+
!!! error TS2339: Property 'y' does not exist on type 'C1'.
51+
~
52+
!!! error TS2339: Property 'z' does not exist on type 'C1'.
53+
54+
var c2 = new C2(["10", 10, !!10]);
55+
var [c2_x, c2_y, c2_z] = [c2.x, c2.y, c2.z];
56+
~
57+
!!! error TS2339: Property 'x' does not exist on type 'C2'.
58+
~
59+
!!! error TS2339: Property 'y' does not exist on type 'C2'.
60+
~
61+
!!! error TS2339: Property 'z' does not exist on type 'C2'.
62+
63+
var c3 = new C3({x: 0, y: "", z: false});
64+
c3 = new C3({x: 0, "y": "y", z: true});
65+
var [c3_x, c3_y, c3_z] = [c3.x, c3.y, c3.z];
66+
~
67+
!!! error TS2339: Property 'x' does not exist on type 'C3'.
68+
~
69+
!!! error TS2339: Property 'y' does not exist on type 'C3'.
70+
~
71+
!!! error TS2339: Property 'z' does not exist on type 'C3'.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//// [destructuringParameterProperties1.ts]
2+
class C1 {
3+
constructor(public [x, y, z]: string[]) {
4+
}
5+
}
6+
7+
type TupleType1 = [string, number, boolean];
8+
9+
class C2 {
10+
constructor(public [x, y, z]: TupleType1) {
11+
}
12+
}
13+
14+
type ObjType1 = { x: number; y: string; z: boolean }
15+
16+
class C3 {
17+
constructor(public { x, y, z }: ObjType1) {
18+
}
19+
}
20+
21+
var c1 = new C1([]);
22+
c1 = new C1(["larry", "{curly}", "moe"]);
23+
var useC1Properties = c1.x === c1.y && c1.y === c1.z;
24+
25+
var c2 = new C2(["10", 10, !!10]);
26+
var [c2_x, c2_y, c2_z] = [c2.x, c2.y, c2.z];
27+
28+
var c3 = new C3({x: 0, y: "", z: false});
29+
c3 = new C3({x: 0, "y": "y", z: true});
30+
var [c3_x, c3_y, c3_z] = [c3.x, c3.y, c3.z];
31+
32+
//// [destructuringParameterProperties1.js]
33+
var C1 = (function () {
34+
function C1(_a) {
35+
var x = _a[0], y = _a[1], z = _a[2];
36+
this.[x, y, z] = [x, y, z];
37+
}
38+
return C1;
39+
})();
40+
var C2 = (function () {
41+
function C2(_a) {
42+
var x = _a[0], y = _a[1], z = _a[2];
43+
this.[x, y, z] = [x, y, z];
44+
}
45+
return C2;
46+
})();
47+
var C3 = (function () {
48+
function C3(_a) {
49+
var x = _a.x, y = _a.y, z = _a.z;
50+
this.{ x, y, z } = { x, y, z };
51+
}
52+
return C3;
53+
})();
54+
var c1 = new C1([]);
55+
c1 = new C1(["larry", "{curly}", "moe"]);
56+
var useC1Properties = c1.x === c1.y && c1.y === c1.z;
57+
var c2 = new C2(["10", 10, !!10]);
58+
var _a = [c2.x, c2.y, c2.z], c2_x = _a[0], c2_y = _a[1], c2_z = _a[2];
59+
var c3 = new C3({ x: 0, y: "", z: false });
60+
c3 = new C3({ x: 0, "y": "y", z: true });
61+
var _b = [c3.x, c3.y, c3.z], c3_x = _b[0], c3_y = _b[1], c3_z = _b[2];
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties2.ts(2,36): error TS1187: A parameter property may not be a binding pattern.
2+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties2.ts(3,59): error TS2339: Property 'b' does not exist on type 'C1'.
3+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties2.ts(3,83): error TS2339: Property 'c' does not exist on type 'C1'.
4+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties2.ts(4,18): error TS2339: Property 'a' does not exist on type 'C1'.
5+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties2.ts(9,21): error TS2339: Property 'a' does not exist on type 'C1'.
6+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties2.ts(13,21): error TS2339: Property 'b' does not exist on type 'C1'.
7+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties2.ts(17,21): error TS2339: Property 'c' does not exist on type 'C1'.
8+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties2.ts(21,27): error TS2345: Argument of type '[number, undefined, string]' is not assignable to parameter of type '[number, string, boolean]'.
9+
10+
11+
==== tests/cases/conformance/es6/destructuring/destructuringParameterProperties2.ts (8 errors) ====
12+
class C1 {
13+
constructor(private k: number, private [a, b, c]: [number, string, boolean]) {
14+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
15+
!!! error TS1187: A parameter property may not be a binding pattern.
16+
if ((b === undefined && c === undefined) || (this.b === undefined && this.c === undefined)) {
17+
~
18+
!!! error TS2339: Property 'b' does not exist on type 'C1'.
19+
~
20+
!!! error TS2339: Property 'c' does not exist on type 'C1'.
21+
this.a = a || k;
22+
~
23+
!!! error TS2339: Property 'a' does not exist on type 'C1'.
24+
}
25+
}
26+
27+
public getA() {
28+
return this.a
29+
~
30+
!!! error TS2339: Property 'a' does not exist on type 'C1'.
31+
}
32+
33+
public getB() {
34+
return this.b
35+
~
36+
!!! error TS2339: Property 'b' does not exist on type 'C1'.
37+
}
38+
39+
public getC() {
40+
return this.c;
41+
~
42+
!!! error TS2339: Property 'c' does not exist on type 'C1'.
43+
}
44+
}
45+
46+
var x = new C1(undefined, [0, undefined, ""]);
47+
~~~~~~~~~~~~~~~~~~
48+
!!! error TS2345: Argument of type '[number, undefined, string]' is not assignable to parameter of type '[number, string, boolean]'.
49+
var [x_a, x_b, x_c] = [x.getA(), x.getB(), x.getC()];
50+
51+
var y = new C1(10, [0, "", true]);
52+
var [y_a, y_b, y_c] = [y.getA(), y.getB(), y.getC()];
53+
54+
var z = new C1(10, [undefined, "", null]);
55+
var [z_a, z_b, z_c] = [z.getA(), z.getB(), z.getC()];
56+
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//// [destructuringParameterProperties2.ts]
2+
class C1 {
3+
constructor(private k: number, private [a, b, c]: [number, string, boolean]) {
4+
if ((b === undefined && c === undefined) || (this.b === undefined && this.c === undefined)) {
5+
this.a = a || k;
6+
}
7+
}
8+
9+
public getA() {
10+
return this.a
11+
}
12+
13+
public getB() {
14+
return this.b
15+
}
16+
17+
public getC() {
18+
return this.c;
19+
}
20+
}
21+
22+
var x = new C1(undefined, [0, undefined, ""]);
23+
var [x_a, x_b, x_c] = [x.getA(), x.getB(), x.getC()];
24+
25+
var y = new C1(10, [0, "", true]);
26+
var [y_a, y_b, y_c] = [y.getA(), y.getB(), y.getC()];
27+
28+
var z = new C1(10, [undefined, "", null]);
29+
var [z_a, z_b, z_c] = [z.getA(), z.getB(), z.getC()];
30+
31+
32+
//// [destructuringParameterProperties2.js]
33+
var C1 = (function () {
34+
function C1(k, _a) {
35+
var a = _a[0], b = _a[1], c = _a[2];
36+
this.k = k;
37+
this.[a, b, c] = [a, b, c];
38+
if ((b === undefined && c === undefined) || (this.b === undefined && this.c === undefined)) {
39+
this.a = a || k;
40+
}
41+
}
42+
C1.prototype.getA = function () {
43+
return this.a;
44+
};
45+
C1.prototype.getB = function () {
46+
return this.b;
47+
};
48+
C1.prototype.getC = function () {
49+
return this.c;
50+
};
51+
return C1;
52+
})();
53+
var x = new C1(undefined, [0, undefined, ""]);
54+
var _a = [x.getA(), x.getB(), x.getC()], x_a = _a[0], x_b = _a[1], x_c = _a[2];
55+
var y = new C1(10, [0, "", true]);
56+
var _b = [y.getA(), y.getB(), y.getC()], y_a = _b[0], y_b = _b[1], y_c = _b[2];
57+
var z = new C1(10, [undefined, "", null]);
58+
var _c = [z.getA(), z.getB(), z.getC()], z_a = _c[0], z_b = _c[1], z_c = _c[2];
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties3.ts(2,31): error TS1187: A parameter property may not be a binding pattern.
2+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties3.ts(3,59): error TS2339: Property 'b' does not exist on type 'C1<T, U, V>'.
3+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties3.ts(3,83): error TS2339: Property 'c' does not exist on type 'C1<T, U, V>'.
4+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties3.ts(4,18): error TS2339: Property 'a' does not exist on type 'C1<T, U, V>'.
5+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties3.ts(9,21): error TS2339: Property 'a' does not exist on type 'C1<T, U, V>'.
6+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties3.ts(13,21): error TS2339: Property 'b' does not exist on type 'C1<T, U, V>'.
7+
tests/cases/conformance/es6/destructuring/destructuringParameterProperties3.ts(17,21): error TS2339: Property 'c' does not exist on type 'C1<T, U, V>'.
8+
9+
10+
==== tests/cases/conformance/es6/destructuring/destructuringParameterProperties3.ts (7 errors) ====
11+
class C1<T, U, V> {
12+
constructor(private k: T, private [a, b, c]: [T,U,V]) {
13+
~~~~~~~~~~~~~~~~~~~~~~~~~~
14+
!!! error TS1187: A parameter property may not be a binding pattern.
15+
if ((b === undefined && c === undefined) || (this.b === undefined && this.c === undefined)) {
16+
~
17+
!!! error TS2339: Property 'b' does not exist on type 'C1<T, U, V>'.
18+
~
19+
!!! error TS2339: Property 'c' does not exist on type 'C1<T, U, V>'.
20+
this.a = a || k;
21+
~
22+
!!! error TS2339: Property 'a' does not exist on type 'C1<T, U, V>'.
23+
}
24+
}
25+
26+
public getA() {
27+
return this.a
28+
~
29+
!!! error TS2339: Property 'a' does not exist on type 'C1<T, U, V>'.
30+
}
31+
32+
public getB() {
33+
return this.b
34+
~
35+
!!! error TS2339: Property 'b' does not exist on type 'C1<T, U, V>'.
36+
}
37+
38+
public getC() {
39+
return this.c;
40+
~
41+
!!! error TS2339: Property 'c' does not exist on type 'C1<T, U, V>'.
42+
}
43+
}
44+
45+
var x = new C1(undefined, [0, true, ""]);
46+
var [x_a, x_b, x_c] = [x.getA(), x.getB(), x.getC()];
47+
48+
var y = new C1(10, [0, true, true]);
49+
var [y_a, y_b, y_c] = [y.getA(), y.getB(), y.getC()];
50+
51+
var z = new C1(10, [undefined, "", ""]);
52+
var [z_a, z_b, z_c] = [z.getA(), z.getB(), z.getC()];
53+
54+
var w = new C1(10, [undefined, undefined, undefined]);
55+
var [z_a, z_b, z_c] = [z.getA(), z.getB(), z.getC()];
56+

0 commit comments

Comments
 (0)