Skip to content

Commit a60e429

Browse files
Merge pull request #61 from bloomberg/es-private-methods-and-accessors-get-error
Added error for using a set only accessor.
2 parents 89f746a + ff24636 commit a60e429

File tree

9 files changed

+455
-5
lines changed

9 files changed

+455
-5
lines changed

src/compiler/checker.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26815,6 +26815,12 @@ namespace ts {
2681526815
if (!prop && checkPrivateIdentifierPropertyAccess(leftType, right, lexicallyScopedSymbol)) {
2681626816
return errorType;
2681726817
}
26818+
else {
26819+
const isSetonlyAccessor = prop && prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor);
26820+
if (isSetonlyAccessor && !isAssignmentTarget(node)) {
26821+
error(node, Diagnostics.Private_accessor_was_defined_without_a_getter);
26822+
}
26823+
}
2681826824
}
2681926825
else {
2682026826
if (isAnyLike) {

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3296,6 +3296,10 @@
32963296
"category": "Error",
32973297
"code": 2805
32983298
},
3299+
"Private accessor was defined without a getter.": {
3300+
"category": "Error",
3301+
"code": 2806
3302+
},
32993303

33003304
"Import declaration '{0}' is using private name '{1}'.": {
33013305
"category": "Error",

src/compiler/utilities.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2706,6 +2706,9 @@ namespace ts {
27062706
case SyntaxKind.NonNullExpression:
27072707
node = parent;
27082708
break;
2709+
case SyntaxKind.SpreadAssignment:
2710+
node = parent.parent;
2711+
break;
27092712
case SyntaxKind.ShorthandPropertyAssignment:
27102713
if ((parent as ShorthandPropertyAssignment).name !== node) {
27112714
return AssignmentKind.None;
@@ -4814,6 +4817,9 @@ namespace ts {
48144817
&& isLeftHandSideExpression(node.left);
48154818
}
48164819

4820+
export function isLeftHandSideOfAssignment(node: Node) {
4821+
return isAssignmentExpression(node.parent) && node.parent.left === node;
4822+
}
48174823
export function isDestructuringAssignment(node: Node): node is DestructuringAssignment {
48184824
if (isAssignmentExpression(node, /*excludeCompoundAssignment*/ true)) {
48194825
const kind = node.left.kind;
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
tests/cases/conformance/classes/members/privateNames/privateWriteOnlyAccessorRead.ts(8,17): error TS2806: Private accessor was defined without a getter.
2+
tests/cases/conformance/classes/members/privateNames/privateWriteOnlyAccessorRead.ts(11,5): error TS2806: Private accessor was defined without a getter.
3+
tests/cases/conformance/classes/members/privateNames/privateWriteOnlyAccessorRead.ts(16,13): error TS2806: Private accessor was defined without a getter.
4+
tests/cases/conformance/classes/members/privateNames/privateWriteOnlyAccessorRead.ts(18,17): error TS2806: Private accessor was defined without a getter.
5+
tests/cases/conformance/classes/members/privateNames/privateWriteOnlyAccessorRead.ts(21,18): error TS2806: Private accessor was defined without a getter.
6+
tests/cases/conformance/classes/members/privateNames/privateWriteOnlyAccessorRead.ts(25,9): error TS2806: Private accessor was defined without a getter.
7+
tests/cases/conformance/classes/members/privateNames/privateWriteOnlyAccessorRead.ts(26,12): error TS2806: Private accessor was defined without a getter.
8+
9+
10+
==== tests/cases/conformance/classes/members/privateNames/privateWriteOnlyAccessorRead.ts (7 errors) ====
11+
class Test {
12+
set #value(v: { foo: { bar: number } }) {}
13+
set #valueRest(v: number[]) {}
14+
set #valueOne(v: number) {}
15+
16+
m() {
17+
const foo = { bar: 1 };
18+
console.log(this.#value); // error
19+
~~~~~~~~~~~
20+
!!! error TS2806: Private accessor was defined without a getter.
21+
this.#value = { foo }; // ok
22+
this.#value = { foo }; // ok
23+
this.#value.foo = foo; // error
24+
~~~~~~~~~~~
25+
!!! error TS2806: Private accessor was defined without a getter.
26+
27+
({ o: this.#value } = { o: { foo } }); //ok
28+
({ ...this.#value } = { foo }); //ok
29+
30+
({ foo: this.#value.foo } = { foo }); //error
31+
~~~~~~~~~~~
32+
!!! error TS2806: Private accessor was defined without a getter.
33+
({
34+
foo: { ...this.#value.foo },
35+
~~~~~~~~~~~
36+
!!! error TS2806: Private accessor was defined without a getter.
37+
} = { foo }); //error
38+
39+
let r = { o: this.#value }; //error
40+
~~~~~~~~~~~
41+
!!! error TS2806: Private accessor was defined without a getter.
42+
43+
[this.#valueOne, ...this.#valueRest] = [1, 2, 3];
44+
let arr = [
45+
this.#valueOne,
46+
~~~~~~~~~~~~~~
47+
!!! error TS2806: Private accessor was defined without a getter.
48+
...this.#valueRest
49+
~~~~~~~~~~~~~~~
50+
!!! error TS2806: Private accessor was defined without a getter.
51+
];
52+
}
53+
}
54+
new Test().m();
55+
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
//// [privateWriteOnlyAccessorRead.ts]
2+
class Test {
3+
set #value(v: { foo: { bar: number } }) {}
4+
set #valueRest(v: number[]) {}
5+
set #valueOne(v: number) {}
6+
7+
m() {
8+
const foo = { bar: 1 };
9+
console.log(this.#value); // error
10+
this.#value = { foo }; // ok
11+
this.#value = { foo }; // ok
12+
this.#value.foo = foo; // error
13+
14+
({ o: this.#value } = { o: { foo } }); //ok
15+
({ ...this.#value } = { foo }); //ok
16+
17+
({ foo: this.#value.foo } = { foo }); //error
18+
({
19+
foo: { ...this.#value.foo },
20+
} = { foo }); //error
21+
22+
let r = { o: this.#value }; //error
23+
24+
[this.#valueOne, ...this.#valueRest] = [1, 2, 3];
25+
let arr = [
26+
this.#valueOne,
27+
...this.#valueRest
28+
];
29+
}
30+
}
31+
new Test().m();
32+
33+
34+
//// [privateWriteOnlyAccessorRead.js]
35+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
36+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
37+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
38+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
39+
};
40+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
41+
if (kind === "m") throw new TypeError("Private method is not writable");
42+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
43+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
44+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
45+
};
46+
var __rest = (this && this.__rest) || function (s, e) {
47+
var t = {};
48+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
49+
t[p] = s[p];
50+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
51+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
52+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
53+
t[p[i]] = s[p[i]];
54+
}
55+
return t;
56+
};
57+
var _Test_instances, _Test_value_set, _Test_valueRest_set, _Test_valueOne_set;
58+
class Test {
59+
constructor() {
60+
_Test_instances.add(this);
61+
}
62+
m() {
63+
var _a, _b, _c;
64+
const foo = { bar: 1 };
65+
console.log(__classPrivateFieldGet(this, _Test_instances, "a")); // error
66+
__classPrivateFieldSet(// error
67+
this, _Test_instances, { foo }, "a", _Test_value_set); // ok
68+
__classPrivateFieldSet(// ok
69+
this, _Test_instances, { foo }, "a", _Test_value_set); // ok
70+
__classPrivateFieldGet(// ok
71+
this, _Test_instances, "a").foo = foo; // error
72+
(_a = this, { o: ({ set value(_d) { __classPrivateFieldSet(_a, _Test_instances, _d, "a", _Test_value_set); } }).value } = { o: { foo } }); //ok
73+
(__classPrivateFieldGet(this, _Test_instances, "a") = __rest({ foo }, [])); //ok
74+
({ foo: __classPrivateFieldGet(this, _Test_instances, "a").foo } = { foo }); //error
75+
({
76+
foo: Object.assign({}, __classPrivateFieldGet(this, _Test_instances, "a").foo),
77+
} = { foo }); //error
78+
let r = { o: __classPrivateFieldGet(this, _Test_instances, "a") }; //error
79+
_b = this, _c = this, [({ set value(_d) { __classPrivateFieldSet(_b, _Test_instances, _d, "a", _Test_valueOne_set); } }).value, ...({ set value(_d) { __classPrivateFieldSet(_c, _Test_instances, _d, "a", _Test_valueRest_set); } }).value] = [1, 2, 3];
80+
let arr = [
81+
__classPrivateFieldGet(this, _Test_instances, "a"),
82+
...__classPrivateFieldGet(this, _Test_instances, "a")
83+
];
84+
}
85+
}
86+
_Test_instances = new WeakSet(), _Test_value_set = function _Test_value_set(v) { }, _Test_valueRest_set = function _Test_valueRest_set(v) { }, _Test_valueOne_set = function _Test_valueOne_set(v) { };
87+
new Test().m();
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
=== tests/cases/conformance/classes/members/privateNames/privateWriteOnlyAccessorRead.ts ===
2+
class Test {
3+
>Test : Symbol(Test, Decl(privateWriteOnlyAccessorRead.ts, 0, 0))
4+
5+
set #value(v: { foo: { bar: number } }) {}
6+
>#value : Symbol(Test.#value, Decl(privateWriteOnlyAccessorRead.ts, 0, 12))
7+
>v : Symbol(v, Decl(privateWriteOnlyAccessorRead.ts, 1, 13))
8+
>foo : Symbol(foo, Decl(privateWriteOnlyAccessorRead.ts, 1, 17))
9+
>bar : Symbol(bar, Decl(privateWriteOnlyAccessorRead.ts, 1, 24))
10+
11+
set #valueRest(v: number[]) {}
12+
>#valueRest : Symbol(Test.#valueRest, Decl(privateWriteOnlyAccessorRead.ts, 1, 44))
13+
>v : Symbol(v, Decl(privateWriteOnlyAccessorRead.ts, 2, 17))
14+
15+
set #valueOne(v: number) {}
16+
>#valueOne : Symbol(Test.#valueOne, Decl(privateWriteOnlyAccessorRead.ts, 2, 32))
17+
>v : Symbol(v, Decl(privateWriteOnlyAccessorRead.ts, 3, 16))
18+
19+
m() {
20+
>m : Symbol(Test.m, Decl(privateWriteOnlyAccessorRead.ts, 3, 29))
21+
22+
const foo = { bar: 1 };
23+
>foo : Symbol(foo, Decl(privateWriteOnlyAccessorRead.ts, 6, 9))
24+
>bar : Symbol(bar, Decl(privateWriteOnlyAccessorRead.ts, 6, 17))
25+
26+
console.log(this.#value); // error
27+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
28+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
29+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
30+
>this.#value : Symbol(Test.#value, Decl(privateWriteOnlyAccessorRead.ts, 0, 12))
31+
>this : Symbol(Test, Decl(privateWriteOnlyAccessorRead.ts, 0, 0))
32+
33+
this.#value = { foo }; // ok
34+
>this.#value : Symbol(Test.#value, Decl(privateWriteOnlyAccessorRead.ts, 0, 12))
35+
>this : Symbol(Test, Decl(privateWriteOnlyAccessorRead.ts, 0, 0))
36+
>foo : Symbol(foo, Decl(privateWriteOnlyAccessorRead.ts, 8, 19))
37+
38+
this.#value = { foo }; // ok
39+
>this.#value : Symbol(Test.#value, Decl(privateWriteOnlyAccessorRead.ts, 0, 12))
40+
>this : Symbol(Test, Decl(privateWriteOnlyAccessorRead.ts, 0, 0))
41+
>foo : Symbol(foo, Decl(privateWriteOnlyAccessorRead.ts, 9, 19))
42+
43+
this.#value.foo = foo; // error
44+
>this.#value.foo : Symbol(foo, Decl(privateWriteOnlyAccessorRead.ts, 1, 17))
45+
>this.#value : Symbol(Test.#value, Decl(privateWriteOnlyAccessorRead.ts, 0, 12))
46+
>this : Symbol(Test, Decl(privateWriteOnlyAccessorRead.ts, 0, 0))
47+
>foo : Symbol(foo, Decl(privateWriteOnlyAccessorRead.ts, 1, 17))
48+
>foo : Symbol(foo, Decl(privateWriteOnlyAccessorRead.ts, 6, 9))
49+
50+
({ o: this.#value } = { o: { foo } }); //ok
51+
>o : Symbol(o, Decl(privateWriteOnlyAccessorRead.ts, 12, 6))
52+
>this.#value : Symbol(Test.#value, Decl(privateWriteOnlyAccessorRead.ts, 0, 12))
53+
>this : Symbol(Test, Decl(privateWriteOnlyAccessorRead.ts, 0, 0))
54+
>o : Symbol(o, Decl(privateWriteOnlyAccessorRead.ts, 12, 27))
55+
>foo : Symbol(foo, Decl(privateWriteOnlyAccessorRead.ts, 12, 32))
56+
57+
({ ...this.#value } = { foo }); //ok
58+
>this.#value : Symbol(Test.#value, Decl(privateWriteOnlyAccessorRead.ts, 0, 12))
59+
>this : Symbol(Test, Decl(privateWriteOnlyAccessorRead.ts, 0, 0))
60+
>foo : Symbol(foo, Decl(privateWriteOnlyAccessorRead.ts, 13, 27))
61+
62+
({ foo: this.#value.foo } = { foo }); //error
63+
>foo : Symbol(foo, Decl(privateWriteOnlyAccessorRead.ts, 15, 6))
64+
>this.#value.foo : Symbol(foo, Decl(privateWriteOnlyAccessorRead.ts, 1, 17))
65+
>this.#value : Symbol(Test.#value, Decl(privateWriteOnlyAccessorRead.ts, 0, 12))
66+
>this : Symbol(Test, Decl(privateWriteOnlyAccessorRead.ts, 0, 0))
67+
>foo : Symbol(foo, Decl(privateWriteOnlyAccessorRead.ts, 1, 17))
68+
>foo : Symbol(foo, Decl(privateWriteOnlyAccessorRead.ts, 15, 33))
69+
70+
({
71+
foo: { ...this.#value.foo },
72+
>foo : Symbol(foo, Decl(privateWriteOnlyAccessorRead.ts, 16, 6))
73+
>this.#value.foo : Symbol(foo, Decl(privateWriteOnlyAccessorRead.ts, 1, 17))
74+
>this.#value : Symbol(Test.#value, Decl(privateWriteOnlyAccessorRead.ts, 0, 12))
75+
>this : Symbol(Test, Decl(privateWriteOnlyAccessorRead.ts, 0, 0))
76+
>foo : Symbol(foo, Decl(privateWriteOnlyAccessorRead.ts, 1, 17))
77+
78+
} = { foo }); //error
79+
>foo : Symbol(foo, Decl(privateWriteOnlyAccessorRead.ts, 18, 9))
80+
81+
let r = { o: this.#value }; //error
82+
>r : Symbol(r, Decl(privateWriteOnlyAccessorRead.ts, 20, 7))
83+
>o : Symbol(o, Decl(privateWriteOnlyAccessorRead.ts, 20, 13))
84+
>this.#value : Symbol(Test.#value, Decl(privateWriteOnlyAccessorRead.ts, 0, 12))
85+
>this : Symbol(Test, Decl(privateWriteOnlyAccessorRead.ts, 0, 0))
86+
87+
[this.#valueOne, ...this.#valueRest] = [1, 2, 3];
88+
>this.#valueOne : Symbol(Test.#valueOne, Decl(privateWriteOnlyAccessorRead.ts, 2, 32))
89+
>this : Symbol(Test, Decl(privateWriteOnlyAccessorRead.ts, 0, 0))
90+
>this.#valueRest : Symbol(Test.#valueRest, Decl(privateWriteOnlyAccessorRead.ts, 1, 44))
91+
>this : Symbol(Test, Decl(privateWriteOnlyAccessorRead.ts, 0, 0))
92+
93+
let arr = [
94+
>arr : Symbol(arr, Decl(privateWriteOnlyAccessorRead.ts, 23, 7))
95+
96+
this.#valueOne,
97+
>this.#valueOne : Symbol(Test.#valueOne, Decl(privateWriteOnlyAccessorRead.ts, 2, 32))
98+
>this : Symbol(Test, Decl(privateWriteOnlyAccessorRead.ts, 0, 0))
99+
100+
...this.#valueRest
101+
>this.#valueRest : Symbol(Test.#valueRest, Decl(privateWriteOnlyAccessorRead.ts, 1, 44))
102+
>this : Symbol(Test, Decl(privateWriteOnlyAccessorRead.ts, 0, 0))
103+
104+
];
105+
}
106+
}
107+
new Test().m();
108+
>new Test().m : Symbol(Test.m, Decl(privateWriteOnlyAccessorRead.ts, 3, 29))
109+
>Test : Symbol(Test, Decl(privateWriteOnlyAccessorRead.ts, 0, 0))
110+
>m : Symbol(Test.m, Decl(privateWriteOnlyAccessorRead.ts, 3, 29))
111+

0 commit comments

Comments
 (0)