From 3d5ac88d1bfcf649d700c419c5ebc439e2a66717 Mon Sep 17 00:00:00 2001 From: Psychpsyo <60073468+Psychpsyo@users.noreply.github.com> Date: Thu, 17 Oct 2024 23:31:00 +0200 Subject: [PATCH 1/3] Allow private properties in optional chains --- src/compiler/diagnosticMessages.json | 4 --- src/compiler/parser.ts | 3 -- .../privateIdentifierChain.1.errors.txt | 28 ------------------- .../reference/privateIdentifierChain.1.js | 16 +++++++---- .../privateIdentifierChain.1.symbols | 13 +++++++-- .../reference/privateIdentifierChain.1.types | 27 +++++++++++++----- ...ateNameUncheckedJsOptionalChain.errors.txt | 17 ----------- .../privateNameUncheckedJsOptionalChain.types | 5 +--- .../privateIdentifierChain.1.ts | 8 ++++-- 9 files changed, 46 insertions(+), 75 deletions(-) delete mode 100644 tests/baselines/reference/privateIdentifierChain.1.errors.txt delete mode 100644 tests/baselines/reference/privateNameUncheckedJsOptionalChain.errors.txt diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 7f686076f1824..d620376f3602b 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -8322,10 +8322,6 @@ "category": "Error", "code": 18029 }, - "An optional chain cannot contain private identifiers.": { - "category": "Error", - "code": 18030 - }, "The intersection '{0}' was reduced to 'never' because property '{1}' has conflicting types in some constituents.": { "category": "Error", "code": 18031 diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 59ad1f030220f..91be37e3da197 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -6405,9 +6405,6 @@ namespace Parser { const propertyAccess = isOptionalChain ? factoryCreatePropertyAccessChain(expression, questionDotToken, name) : factoryCreatePropertyAccessExpression(expression, name); - if (isOptionalChain && isPrivateIdentifier(propertyAccess.name)) { - parseErrorAtRange(propertyAccess.name, Diagnostics.An_optional_chain_cannot_contain_private_identifiers); - } if (isExpressionWithTypeArguments(expression) && expression.typeArguments) { const pos = expression.typeArguments.pos - 1; const end = skipTrivia(sourceText, expression.typeArguments.end) + 1; diff --git a/tests/baselines/reference/privateIdentifierChain.1.errors.txt b/tests/baselines/reference/privateIdentifierChain.1.errors.txt deleted file mode 100644 index f39beb93eda6c..0000000000000 --- a/tests/baselines/reference/privateIdentifierChain.1.errors.txt +++ /dev/null @@ -1,28 +0,0 @@ -privateIdentifierChain.1.ts(8,15): error TS18030: An optional chain cannot contain private identifiers. -privateIdentifierChain.1.ts(9,9): error TS2532: Object is possibly 'undefined'. -privateIdentifierChain.1.ts(9,17): error TS18030: An optional chain cannot contain private identifiers. -privateIdentifierChain.1.ts(10,22): error TS18030: An optional chain cannot contain private identifiers. - - -==== privateIdentifierChain.1.ts (4 errors) ==== - class A { - a?: A - #b?: A; - getA(): A { - return new A(); - } - constructor() { - this?.#b; // Error - ~~ -!!! error TS18030: An optional chain cannot contain private identifiers. - this?.a.#b; // Error - ~~~~~~~ -!!! error TS2532: Object is possibly 'undefined'. - ~~ -!!! error TS18030: An optional chain cannot contain private identifiers. - this?.getA().#b; // Error - ~~ -!!! error TS18030: An optional chain cannot contain private identifiers. - } - } - \ No newline at end of file diff --git a/tests/baselines/reference/privateIdentifierChain.1.js b/tests/baselines/reference/privateIdentifierChain.1.js index 37e85cb1096c7..1ea67a244b7b6 100644 --- a/tests/baselines/reference/privateIdentifierChain.1.js +++ b/tests/baselines/reference/privateIdentifierChain.1.js @@ -8,9 +8,11 @@ class A { return new A(); } constructor() { - this?.#b; // Error - this?.a.#b; // Error - this?.getA().#b; // Error + this.a = this; + // None of these should error + this?.#b; + this?.a.#b; + this?.getA().#b; } } @@ -23,8 +25,10 @@ class A { return new A(); } constructor() { - this?.#b; // Error - this?.a.#b; // Error - this?.getA().#b; // Error + this.a = this; + // None of these should error + this?.#b; + this?.a.#b; + this?.getA().#b; } } diff --git a/tests/baselines/reference/privateIdentifierChain.1.symbols b/tests/baselines/reference/privateIdentifierChain.1.symbols index 018ca51f62f21..3a5fb46551aec 100644 --- a/tests/baselines/reference/privateIdentifierChain.1.symbols +++ b/tests/baselines/reference/privateIdentifierChain.1.symbols @@ -20,17 +20,24 @@ class A { >A : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0)) } constructor() { - this?.#b; // Error + this.a = this; +>this.a : Symbol(A.a, Decl(privateIdentifierChain.1.ts, 0, 9)) +>this : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0)) +>a : Symbol(A.a, Decl(privateIdentifierChain.1.ts, 0, 9)) +>this : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0)) + + // None of these should error + this?.#b; >this?.#b : Symbol(A.#b, Decl(privateIdentifierChain.1.ts, 1, 9)) >this : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0)) - this?.a.#b; // Error + this?.a.#b; >this?.a.#b : Symbol(A.#b, Decl(privateIdentifierChain.1.ts, 1, 9)) >this?.a : Symbol(A.a, Decl(privateIdentifierChain.1.ts, 0, 9)) >this : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0)) >a : Symbol(A.a, Decl(privateIdentifierChain.1.ts, 0, 9)) - this?.getA().#b; // Error + this?.getA().#b; >this?.getA().#b : Symbol(A.#b, Decl(privateIdentifierChain.1.ts, 1, 9)) >this?.getA : Symbol(A.getA, Decl(privateIdentifierChain.1.ts, 2, 11)) >this : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0)) diff --git a/tests/baselines/reference/privateIdentifierChain.1.types b/tests/baselines/reference/privateIdentifierChain.1.types index 70827d3bcbc0c..3a7b58bae956f 100644 --- a/tests/baselines/reference/privateIdentifierChain.1.types +++ b/tests/baselines/reference/privateIdentifierChain.1.types @@ -24,23 +24,36 @@ class A { > : ^^^^^^^^ } constructor() { - this?.#b; // Error + this.a = this; +>this.a = this : this +> : ^^^^ +>this.a : A | undefined +> : ^^^^^^^^^^^^^ +>this : this +> : ^^^^ +>a : A | undefined +> : ^^^^^^^^^^^^^ +>this : this +> : ^^^^ + + // None of these should error + this?.#b; >this?.#b : A | undefined > : ^^^^^^^^^^^^^ >this : this > : ^^^^ - this?.a.#b; // Error + this?.a.#b; >this?.a.#b : A | undefined > : ^^^^^^^^^^^^^ ->this?.a : A | undefined -> : ^^^^^^^^^^^^^ +>this?.a : A +> : ^ >this : this > : ^^^^ ->a : A | undefined -> : ^^^^^^^^^^^^^ +>a : A +> : ^ - this?.getA().#b; // Error + this?.getA().#b; >this?.getA().#b : A | undefined > : ^^^^^^^^^^^^^ >this?.getA() : A diff --git a/tests/baselines/reference/privateNameUncheckedJsOptionalChain.errors.txt b/tests/baselines/reference/privateNameUncheckedJsOptionalChain.errors.txt deleted file mode 100644 index 13327c6a0151c..0000000000000 --- a/tests/baselines/reference/privateNameUncheckedJsOptionalChain.errors.txt +++ /dev/null @@ -1,17 +0,0 @@ -privateNameUncheckedJsOptionalChain.js(4,15): error TS18030: An optional chain cannot contain private identifiers. -privateNameUncheckedJsOptionalChain.js(5,15): error TS18030: An optional chain cannot contain private identifiers. - - -==== privateNameUncheckedJsOptionalChain.js (2 errors) ==== - class C { - #bar; - constructor () { - this?.#foo; - ~~~~ -!!! error TS18030: An optional chain cannot contain private identifiers. - this?.#bar; - ~~~~ -!!! error TS18030: An optional chain cannot contain private identifiers. - } - } - \ No newline at end of file diff --git a/tests/baselines/reference/privateNameUncheckedJsOptionalChain.types b/tests/baselines/reference/privateNameUncheckedJsOptionalChain.types index cea9ea7054bd5..9dfc318ecca2b 100644 --- a/tests/baselines/reference/privateNameUncheckedJsOptionalChain.types +++ b/tests/baselines/reference/privateNameUncheckedJsOptionalChain.types @@ -7,18 +7,15 @@ class C { #bar; >#bar : any -> : ^^^ constructor () { this?.#foo; ->this?.#foo : any -> : ^^^ +>this?.#foo : error >this : this > : ^^^^ this?.#bar; >this?.#bar : any -> : ^^^ >this : this > : ^^^^ } diff --git a/tests/cases/conformance/expressions/optionalChaining/privateIdentifierChain/privateIdentifierChain.1.ts b/tests/cases/conformance/expressions/optionalChaining/privateIdentifierChain/privateIdentifierChain.1.ts index e98eeba739d5a..047da6bf55ff6 100644 --- a/tests/cases/conformance/expressions/optionalChaining/privateIdentifierChain/privateIdentifierChain.1.ts +++ b/tests/cases/conformance/expressions/optionalChaining/privateIdentifierChain/privateIdentifierChain.1.ts @@ -9,8 +9,10 @@ class A { return new A(); } constructor() { - this?.#b; // Error - this?.a.#b; // Error - this?.getA().#b; // Error + this.a = this; + // None of these should error + this?.#b; + this?.a.#b; + this?.getA().#b; } } From 0156c57f143bcd26ba0fc5788f0d4254621b4f8e Mon Sep 17 00:00:00 2001 From: Psychpsyo <60073468+Psychpsyo@users.noreply.github.com> Date: Fri, 18 Oct 2024 00:03:14 +0200 Subject: [PATCH 2/3] Fix linter error --- src/compiler/parser.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 91be37e3da197..71fc00c185cea 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -159,7 +159,6 @@ import { isMetaProperty, isModifierKind, isNonNullExpression, - isPrivateIdentifier, isSetAccessorDeclaration, isStringOrNumericLiteralLike, isTaggedTemplateExpression, From e7bd8988bf6988c19595e592c8c83e4a0100f833 Mon Sep 17 00:00:00 2001 From: Psychpsyo <60073468+Psychpsyo@users.noreply.github.com> Date: Mon, 21 Jul 2025 21:34:43 +0200 Subject: [PATCH 3/3] Improve tests for private identifiers in optional chains --- ...dentifierChain.1(target=es2015).errors.txt | 40 ++++++ ...privateIdentifierChain.1(target=es2015).js | 66 +++++++++ ...eIdentifierChain.1(target=es2015).symbols} | 38 +++++ ...ateIdentifierChain.1(target=es2015).types} | 67 +++++++++ ...dentifierChain.1(target=esnext).errors.txt | 40 ++++++ ...rivateIdentifierChain.1(target=esnext).js} | 24 ++++ ...teIdentifierChain.1(target=esnext).symbols | 85 +++++++++++ ...vateIdentifierChain.1(target=esnext).types | 136 ++++++++++++++++++ .../privateIdentifierChain.1.ts | 15 +- 9 files changed, 510 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/privateIdentifierChain.1(target=es2015).errors.txt create mode 100644 tests/baselines/reference/privateIdentifierChain.1(target=es2015).js rename tests/baselines/reference/{privateIdentifierChain.1.symbols => privateIdentifierChain.1(target=es2015).symbols} (54%) rename tests/baselines/reference/{privateIdentifierChain.1.types => privateIdentifierChain.1(target=es2015).types} (51%) create mode 100644 tests/baselines/reference/privateIdentifierChain.1(target=esnext).errors.txt rename tests/baselines/reference/{privateIdentifierChain.1.js => privateIdentifierChain.1(target=esnext).js} (59%) create mode 100644 tests/baselines/reference/privateIdentifierChain.1(target=esnext).symbols create mode 100644 tests/baselines/reference/privateIdentifierChain.1(target=esnext).types diff --git a/tests/baselines/reference/privateIdentifierChain.1(target=es2015).errors.txt b/tests/baselines/reference/privateIdentifierChain.1(target=es2015).errors.txt new file mode 100644 index 0000000000000..add1c398df613 --- /dev/null +++ b/tests/baselines/reference/privateIdentifierChain.1(target=es2015).errors.txt @@ -0,0 +1,40 @@ +privateIdentifierChain.1.ts(23,17): error TS18013: Property '#b' is not accessible outside class 'A' because it has a private identifier. +privateIdentifierChain.1.ts(24,17): error TS18013: Property '#b' is not accessible outside class 'A' because it has a private identifier. +privateIdentifierChain.1.ts(25,22): error TS18013: Property '#b' is not accessible outside class 'A' because it has a private identifier. + + +==== privateIdentifierChain.1.ts (3 errors) ==== + class A { + a?: A + #b?: A; + getA(): A { + return new A(); + } + constructor() { + this.a = this; + // None of these should error + this?.#b; + this?.a.#b; + this?.getA().#b; + } + } + + class B { + a?: A + getA(): A { + return new A(); + } + constructor() { + this.a = new A(); + this.a?.#b; // Error + ~~ +!!! error TS18013: Property '#b' is not accessible outside class 'A' because it has a private identifier. + this?.a.#b; // Error + ~~ +!!! error TS18013: Property '#b' is not accessible outside class 'A' because it has a private identifier. + this?.getA().#b; // Error + ~~ +!!! error TS18013: Property '#b' is not accessible outside class 'A' because it has a private identifier. + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/privateIdentifierChain.1(target=es2015).js b/tests/baselines/reference/privateIdentifierChain.1(target=es2015).js new file mode 100644 index 0000000000000..0ba5218faf91c --- /dev/null +++ b/tests/baselines/reference/privateIdentifierChain.1(target=es2015).js @@ -0,0 +1,66 @@ +//// [tests/cases/conformance/expressions/optionalChaining/privateIdentifierChain/privateIdentifierChain.1.ts] //// + +//// [privateIdentifierChain.1.ts] +class A { + a?: A + #b?: A; + getA(): A { + return new A(); + } + constructor() { + this.a = this; + // None of these should error + this?.#b; + this?.a.#b; + this?.getA().#b; + } +} + +class B { + a?: A + getA(): A { + return new A(); + } + constructor() { + this.a = new A(); + this.a?.#b; // Error + this?.a.#b; // Error + this?.getA().#b; // Error + } +} + + +//// [privateIdentifierChain.1.js] +"use strict"; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + 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"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var _A_b; +class A { + getA() { + return new A(); + } + constructor() { + _A_b.set(this, void 0); + this.a = this; + // None of these should error + __classPrivateFieldGet(this, _A_b, "f"); + __classPrivateFieldGet(this === null || this === void 0 ? void 0 : this.a, _A_b, "f"); + __classPrivateFieldGet(this === null || this === void 0 ? void 0 : this.getA(), _A_b, "f"); + } +} +_A_b = new WeakMap(); +class B { + getA() { + return new A(); + } + constructor() { + var _a; + this.a = new A(); + (_a = this.a) === null || _a === void 0 ? void 0 : _a.; // Error + this === null || this === void 0 ? void 0 : this.a.; // Error + this === null || this === void 0 ? void 0 : this.getA().; // Error + } +} diff --git a/tests/baselines/reference/privateIdentifierChain.1.symbols b/tests/baselines/reference/privateIdentifierChain.1(target=es2015).symbols similarity index 54% rename from tests/baselines/reference/privateIdentifierChain.1.symbols rename to tests/baselines/reference/privateIdentifierChain.1(target=es2015).symbols index 3a5fb46551aec..1225ad245a35d 100644 --- a/tests/baselines/reference/privateIdentifierChain.1.symbols +++ b/tests/baselines/reference/privateIdentifierChain.1(target=es2015).symbols @@ -45,3 +45,41 @@ class A { } } +class B { +>B : Symbol(B, Decl(privateIdentifierChain.1.ts, 13, 1)) + + a?: A +>a : Symbol(B.a, Decl(privateIdentifierChain.1.ts, 15, 9)) +>A : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0)) + + getA(): A { +>getA : Symbol(B.getA, Decl(privateIdentifierChain.1.ts, 16, 9)) +>A : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0)) + + return new A(); +>A : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0)) + } + constructor() { + this.a = new A(); +>this.a : Symbol(B.a, Decl(privateIdentifierChain.1.ts, 15, 9)) +>this : Symbol(B, Decl(privateIdentifierChain.1.ts, 13, 1)) +>a : Symbol(B.a, Decl(privateIdentifierChain.1.ts, 15, 9)) +>A : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0)) + + this.a?.#b; // Error +>this.a : Symbol(B.a, Decl(privateIdentifierChain.1.ts, 15, 9)) +>this : Symbol(B, Decl(privateIdentifierChain.1.ts, 13, 1)) +>a : Symbol(B.a, Decl(privateIdentifierChain.1.ts, 15, 9)) + + this?.a.#b; // Error +>this?.a : Symbol(B.a, Decl(privateIdentifierChain.1.ts, 15, 9)) +>this : Symbol(B, Decl(privateIdentifierChain.1.ts, 13, 1)) +>a : Symbol(B.a, Decl(privateIdentifierChain.1.ts, 15, 9)) + + this?.getA().#b; // Error +>this?.getA : Symbol(B.getA, Decl(privateIdentifierChain.1.ts, 16, 9)) +>this : Symbol(B, Decl(privateIdentifierChain.1.ts, 13, 1)) +>getA : Symbol(B.getA, Decl(privateIdentifierChain.1.ts, 16, 9)) + } +} + diff --git a/tests/baselines/reference/privateIdentifierChain.1.types b/tests/baselines/reference/privateIdentifierChain.1(target=es2015).types similarity index 51% rename from tests/baselines/reference/privateIdentifierChain.1.types rename to tests/baselines/reference/privateIdentifierChain.1(target=es2015).types index 3a7b58bae956f..19feefed73ce3 100644 --- a/tests/baselines/reference/privateIdentifierChain.1.types +++ b/tests/baselines/reference/privateIdentifierChain.1(target=es2015).types @@ -67,3 +67,70 @@ class A { } } +class B { +>B : B +> : ^ + + a?: A +>a : A | undefined +> : ^^^^^^^^^^^^^ + + getA(): A { +>getA : () => A +> : ^^^^^^ + + return new A(); +>new A() : A +> : ^ +>A : typeof A +> : ^^^^^^^^ + } + constructor() { + this.a = new A(); +>this.a = new A() : A +> : ^ +>this.a : A | undefined +> : ^^^^^^^^^^^^^ +>this : this +> : ^^^^ +>a : A | undefined +> : ^^^^^^^^^^^^^ +>new A() : A +> : ^ +>A : typeof A +> : ^^^^^^^^ + + this.a?.#b; // Error +>this.a?.#b : any +> : ^^^ +>this.a : A +> : ^ +>this : this +> : ^^^^ +>a : A +> : ^ + + this?.a.#b; // Error +>this?.a.#b : any +> : ^^^ +>this?.a : A +> : ^ +>this : this +> : ^^^^ +>a : A +> : ^ + + this?.getA().#b; // Error +>this?.getA().#b : any +> : ^^^ +>this?.getA() : A +> : ^ +>this?.getA : () => A +> : ^^^^^^ +>this : this +> : ^^^^ +>getA : () => A +> : ^^^^^^ + } +} + diff --git a/tests/baselines/reference/privateIdentifierChain.1(target=esnext).errors.txt b/tests/baselines/reference/privateIdentifierChain.1(target=esnext).errors.txt new file mode 100644 index 0000000000000..add1c398df613 --- /dev/null +++ b/tests/baselines/reference/privateIdentifierChain.1(target=esnext).errors.txt @@ -0,0 +1,40 @@ +privateIdentifierChain.1.ts(23,17): error TS18013: Property '#b' is not accessible outside class 'A' because it has a private identifier. +privateIdentifierChain.1.ts(24,17): error TS18013: Property '#b' is not accessible outside class 'A' because it has a private identifier. +privateIdentifierChain.1.ts(25,22): error TS18013: Property '#b' is not accessible outside class 'A' because it has a private identifier. + + +==== privateIdentifierChain.1.ts (3 errors) ==== + class A { + a?: A + #b?: A; + getA(): A { + return new A(); + } + constructor() { + this.a = this; + // None of these should error + this?.#b; + this?.a.#b; + this?.getA().#b; + } + } + + class B { + a?: A + getA(): A { + return new A(); + } + constructor() { + this.a = new A(); + this.a?.#b; // Error + ~~ +!!! error TS18013: Property '#b' is not accessible outside class 'A' because it has a private identifier. + this?.a.#b; // Error + ~~ +!!! error TS18013: Property '#b' is not accessible outside class 'A' because it has a private identifier. + this?.getA().#b; // Error + ~~ +!!! error TS18013: Property '#b' is not accessible outside class 'A' because it has a private identifier. + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/privateIdentifierChain.1.js b/tests/baselines/reference/privateIdentifierChain.1(target=esnext).js similarity index 59% rename from tests/baselines/reference/privateIdentifierChain.1.js rename to tests/baselines/reference/privateIdentifierChain.1(target=esnext).js index 1ea67a244b7b6..8a4b2049a6c75 100644 --- a/tests/baselines/reference/privateIdentifierChain.1.js +++ b/tests/baselines/reference/privateIdentifierChain.1(target=esnext).js @@ -15,6 +15,19 @@ class A { this?.getA().#b; } } + +class B { + a?: A + getA(): A { + return new A(); + } + constructor() { + this.a = new A(); + this.a?.#b; // Error + this?.a.#b; // Error + this?.getA().#b; // Error + } +} //// [privateIdentifierChain.1.js] @@ -32,3 +45,14 @@ class A { this?.getA().#b; } } +class B { + getA() { + return new A(); + } + constructor() { + this.a = new A(); + this.a?.#b; // Error + this?.a.#b; // Error + this?.getA().#b; // Error + } +} diff --git a/tests/baselines/reference/privateIdentifierChain.1(target=esnext).symbols b/tests/baselines/reference/privateIdentifierChain.1(target=esnext).symbols new file mode 100644 index 0000000000000..1225ad245a35d --- /dev/null +++ b/tests/baselines/reference/privateIdentifierChain.1(target=esnext).symbols @@ -0,0 +1,85 @@ +//// [tests/cases/conformance/expressions/optionalChaining/privateIdentifierChain/privateIdentifierChain.1.ts] //// + +=== privateIdentifierChain.1.ts === +class A { +>A : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0)) + + a?: A +>a : Symbol(A.a, Decl(privateIdentifierChain.1.ts, 0, 9)) +>A : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0)) + + #b?: A; +>#b : Symbol(A.#b, Decl(privateIdentifierChain.1.ts, 1, 9)) +>A : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0)) + + getA(): A { +>getA : Symbol(A.getA, Decl(privateIdentifierChain.1.ts, 2, 11)) +>A : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0)) + + return new A(); +>A : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0)) + } + constructor() { + this.a = this; +>this.a : Symbol(A.a, Decl(privateIdentifierChain.1.ts, 0, 9)) +>this : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0)) +>a : Symbol(A.a, Decl(privateIdentifierChain.1.ts, 0, 9)) +>this : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0)) + + // None of these should error + this?.#b; +>this?.#b : Symbol(A.#b, Decl(privateIdentifierChain.1.ts, 1, 9)) +>this : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0)) + + this?.a.#b; +>this?.a.#b : Symbol(A.#b, Decl(privateIdentifierChain.1.ts, 1, 9)) +>this?.a : Symbol(A.a, Decl(privateIdentifierChain.1.ts, 0, 9)) +>this : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0)) +>a : Symbol(A.a, Decl(privateIdentifierChain.1.ts, 0, 9)) + + this?.getA().#b; +>this?.getA().#b : Symbol(A.#b, Decl(privateIdentifierChain.1.ts, 1, 9)) +>this?.getA : Symbol(A.getA, Decl(privateIdentifierChain.1.ts, 2, 11)) +>this : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0)) +>getA : Symbol(A.getA, Decl(privateIdentifierChain.1.ts, 2, 11)) + } +} + +class B { +>B : Symbol(B, Decl(privateIdentifierChain.1.ts, 13, 1)) + + a?: A +>a : Symbol(B.a, Decl(privateIdentifierChain.1.ts, 15, 9)) +>A : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0)) + + getA(): A { +>getA : Symbol(B.getA, Decl(privateIdentifierChain.1.ts, 16, 9)) +>A : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0)) + + return new A(); +>A : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0)) + } + constructor() { + this.a = new A(); +>this.a : Symbol(B.a, Decl(privateIdentifierChain.1.ts, 15, 9)) +>this : Symbol(B, Decl(privateIdentifierChain.1.ts, 13, 1)) +>a : Symbol(B.a, Decl(privateIdentifierChain.1.ts, 15, 9)) +>A : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0)) + + this.a?.#b; // Error +>this.a : Symbol(B.a, Decl(privateIdentifierChain.1.ts, 15, 9)) +>this : Symbol(B, Decl(privateIdentifierChain.1.ts, 13, 1)) +>a : Symbol(B.a, Decl(privateIdentifierChain.1.ts, 15, 9)) + + this?.a.#b; // Error +>this?.a : Symbol(B.a, Decl(privateIdentifierChain.1.ts, 15, 9)) +>this : Symbol(B, Decl(privateIdentifierChain.1.ts, 13, 1)) +>a : Symbol(B.a, Decl(privateIdentifierChain.1.ts, 15, 9)) + + this?.getA().#b; // Error +>this?.getA : Symbol(B.getA, Decl(privateIdentifierChain.1.ts, 16, 9)) +>this : Symbol(B, Decl(privateIdentifierChain.1.ts, 13, 1)) +>getA : Symbol(B.getA, Decl(privateIdentifierChain.1.ts, 16, 9)) + } +} + diff --git a/tests/baselines/reference/privateIdentifierChain.1(target=esnext).types b/tests/baselines/reference/privateIdentifierChain.1(target=esnext).types new file mode 100644 index 0000000000000..19feefed73ce3 --- /dev/null +++ b/tests/baselines/reference/privateIdentifierChain.1(target=esnext).types @@ -0,0 +1,136 @@ +//// [tests/cases/conformance/expressions/optionalChaining/privateIdentifierChain/privateIdentifierChain.1.ts] //// + +=== privateIdentifierChain.1.ts === +class A { +>A : A +> : ^ + + a?: A +>a : A | undefined +> : ^^^^^^^^^^^^^ + + #b?: A; +>#b : A | undefined +> : ^^^^^^^^^^^^^ + + getA(): A { +>getA : () => A +> : ^^^^^^ + + return new A(); +>new A() : A +> : ^ +>A : typeof A +> : ^^^^^^^^ + } + constructor() { + this.a = this; +>this.a = this : this +> : ^^^^ +>this.a : A | undefined +> : ^^^^^^^^^^^^^ +>this : this +> : ^^^^ +>a : A | undefined +> : ^^^^^^^^^^^^^ +>this : this +> : ^^^^ + + // None of these should error + this?.#b; +>this?.#b : A | undefined +> : ^^^^^^^^^^^^^ +>this : this +> : ^^^^ + + this?.a.#b; +>this?.a.#b : A | undefined +> : ^^^^^^^^^^^^^ +>this?.a : A +> : ^ +>this : this +> : ^^^^ +>a : A +> : ^ + + this?.getA().#b; +>this?.getA().#b : A | undefined +> : ^^^^^^^^^^^^^ +>this?.getA() : A +> : ^ +>this?.getA : () => A +> : ^^^^^^ +>this : this +> : ^^^^ +>getA : () => A +> : ^^^^^^ + } +} + +class B { +>B : B +> : ^ + + a?: A +>a : A | undefined +> : ^^^^^^^^^^^^^ + + getA(): A { +>getA : () => A +> : ^^^^^^ + + return new A(); +>new A() : A +> : ^ +>A : typeof A +> : ^^^^^^^^ + } + constructor() { + this.a = new A(); +>this.a = new A() : A +> : ^ +>this.a : A | undefined +> : ^^^^^^^^^^^^^ +>this : this +> : ^^^^ +>a : A | undefined +> : ^^^^^^^^^^^^^ +>new A() : A +> : ^ +>A : typeof A +> : ^^^^^^^^ + + this.a?.#b; // Error +>this.a?.#b : any +> : ^^^ +>this.a : A +> : ^ +>this : this +> : ^^^^ +>a : A +> : ^ + + this?.a.#b; // Error +>this?.a.#b : any +> : ^^^ +>this?.a : A +> : ^ +>this : this +> : ^^^^ +>a : A +> : ^ + + this?.getA().#b; // Error +>this?.getA().#b : any +> : ^^^ +>this?.getA() : A +> : ^ +>this?.getA : () => A +> : ^^^^^^ +>this : this +> : ^^^^ +>getA : () => A +> : ^^^^^^ + } +} + diff --git a/tests/cases/conformance/expressions/optionalChaining/privateIdentifierChain/privateIdentifierChain.1.ts b/tests/cases/conformance/expressions/optionalChaining/privateIdentifierChain/privateIdentifierChain.1.ts index 047da6bf55ff6..ae0dbe33e0368 100644 --- a/tests/cases/conformance/expressions/optionalChaining/privateIdentifierChain/privateIdentifierChain.1.ts +++ b/tests/cases/conformance/expressions/optionalChaining/privateIdentifierChain/privateIdentifierChain.1.ts @@ -1,5 +1,5 @@ // @strict: true -// @target: esnext +// @target: esnext,es2015 // @useDefineForClassFields: false class A { @@ -16,3 +16,16 @@ class A { this?.getA().#b; } } + +class B { + a?: A + getA(): A { + return new A(); + } + constructor() { + this.a = new A(); + this.a?.#b; // Error + this?.a.#b; // Error + this?.getA().#b; // Error + } +}