Skip to content

Commit f3cdef3

Browse files
author
Joey Watts
committed
Parse error on private identifier optional chain
Previously, this error was reported in the checker, so JS files with checkJs: false were not erroring on this invalid syntax.
1 parent 4585f44 commit f3cdef3

File tree

8 files changed

+74
-8
lines changed

8 files changed

+74
-8
lines changed

src/compiler/checker.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23127,10 +23127,6 @@ namespace ts {
2312723127
const assignmentKind = getAssignmentTargetKind(node);
2312823128
const apparentType = getApparentType(assignmentKind !== AssignmentKind.None || isMethodAccessForCall(node) ? getWidenedType(leftType) : leftType);
2312923129
if (isPrivateIdentifier(right)) {
23130-
if (isOptionalChain(node)) {
23131-
grammarErrorOnNode(right, Diagnostics.An_optional_chain_cannot_contain_private_identifiers);
23132-
return anyType;
23133-
}
2313423130
checkExternalEmitHelpers(node, ExternalEmitHelpers.ClassPrivateFieldGet);
2313523131
}
2313623132
const isAnyLike = isTypeAny(apparentType) || apparentType === silentNeverType;

src/compiler/parser.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4665,10 +4665,12 @@ namespace ts {
46654665
const propertyAccess = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, expression.pos);
46664666
propertyAccess.expression = expression;
46674667
propertyAccess.questionDotToken = questionDotToken;
4668-
// checker will error on private identifiers in optional chains, so don't have to catch them here
46694668
propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true);
46704669
if (questionDotToken || expression.flags & NodeFlags.OptionalChain) {
46714670
propertyAccess.flags |= NodeFlags.OptionalChain;
4671+
if (isPrivateIdentifier(propertyAccess.name)) {
4672+
parseErrorAtRange(propertyAccess.name, Diagnostics.An_optional_chain_cannot_contain_private_identifiers);
4673+
}
46724674
}
46734675
return finishNode(propertyAccess);
46744676
}

tests/baselines/reference/privateIdentifierChain.1.symbols

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,17 @@ class A {
1919
}
2020
constructor() {
2121
this?.#b; // Error
22+
>this?.#b : Symbol(A.#b, Decl(privateIdentifierChain.1.ts, 1, 9))
2223
>this : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0))
2324

2425
this?.a.#b; // Error
26+
>this?.a.#b : Symbol(A.#b, Decl(privateIdentifierChain.1.ts, 1, 9))
2527
>this?.a : Symbol(A.a, Decl(privateIdentifierChain.1.ts, 0, 9))
2628
>this : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0))
2729
>a : Symbol(A.a, Decl(privateIdentifierChain.1.ts, 0, 9))
2830

2931
this?.getA().#b; // Error
32+
>this?.getA().#b : Symbol(A.#b, Decl(privateIdentifierChain.1.ts, 1, 9))
3033
>this?.getA : Symbol(A.getA, Decl(privateIdentifierChain.1.ts, 2, 11))
3134
>this : Symbol(A, Decl(privateIdentifierChain.1.ts, 0, 0))
3235
>getA : Symbol(A.getA, Decl(privateIdentifierChain.1.ts, 2, 11))

tests/baselines/reference/privateIdentifierChain.1.types

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,17 @@ class A {
1717
}
1818
constructor() {
1919
this?.#b; // Error
20-
>this?.#b : any
20+
>this?.#b : A | undefined
2121
>this : this
2222

2323
this?.a.#b; // Error
24-
>this?.a.#b : any
24+
>this?.a.#b : A | undefined
2525
>this?.a : A | undefined
2626
>this : this
2727
>a : A | undefined
2828

2929
this?.getA().#b; // Error
30-
>this?.getA().#b : any
30+
>this?.getA().#b : A | undefined
3131
>this?.getA() : A | undefined
3232
>this?.getA : (() => A) | undefined
3333
>this : this
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
tests/cases/conformance/classes/members/privateNames/privateNameUncheckedJsOptionalChain.js(4,15): error TS18030: An optional chain cannot contain private identifiers.
2+
tests/cases/conformance/classes/members/privateNames/privateNameUncheckedJsOptionalChain.js(5,15): error TS18030: An optional chain cannot contain private identifiers.
3+
4+
5+
==== tests/cases/conformance/classes/members/privateNames/privateNameUncheckedJsOptionalChain.js (2 errors) ====
6+
class C {
7+
#bar;
8+
constructor () {
9+
this?.#foo;
10+
~~~~
11+
!!! error TS18030: An optional chain cannot contain private identifiers.
12+
this?.#bar;
13+
~~~~
14+
!!! error TS18030: An optional chain cannot contain private identifiers.
15+
}
16+
}
17+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
=== tests/cases/conformance/classes/members/privateNames/privateNameUncheckedJsOptionalChain.js ===
2+
class C {
3+
>C : Symbol(C, Decl(privateNameUncheckedJsOptionalChain.js, 0, 0))
4+
5+
#bar;
6+
>#bar : Symbol(C.#bar, Decl(privateNameUncheckedJsOptionalChain.js, 0, 9))
7+
8+
constructor () {
9+
this?.#foo;
10+
>this : Symbol(C, Decl(privateNameUncheckedJsOptionalChain.js, 0, 0))
11+
12+
this?.#bar;
13+
>this?.#bar : Symbol(C.#bar, Decl(privateNameUncheckedJsOptionalChain.js, 0, 9))
14+
>this : Symbol(C, Decl(privateNameUncheckedJsOptionalChain.js, 0, 0))
15+
}
16+
}
17+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
=== tests/cases/conformance/classes/members/privateNames/privateNameUncheckedJsOptionalChain.js ===
2+
class C {
3+
>C : C
4+
5+
#bar;
6+
>#bar : any
7+
8+
constructor () {
9+
this?.#foo;
10+
>this?.#foo : any
11+
>this : this
12+
13+
this?.#bar;
14+
>this?.#bar : any
15+
>this : this
16+
}
17+
}
18+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// @allowJs: true
2+
// @checkJs: false
3+
// @noEmit: true
4+
// @Filename: privateNameUncheckedJsOptionalChain.js
5+
// @target: es2015
6+
7+
class C {
8+
#bar;
9+
constructor () {
10+
this?.#foo;
11+
this?.#bar;
12+
}
13+
}

0 commit comments

Comments
 (0)