diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index fb3c33c01b814..f1afe0d0b9b4b 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -5902,6 +5902,11 @@ func (c *Checker) checkVariableLikeDeclaration(node *ast.Node) { } if ast.IsBindingElement(node) { propName := node.PropertyName() + + if propName != nil && ast.IsPrivateIdentifier(propName) { + c.grammarErrorOnNode(propName, diagnostics.Private_identifiers_cannot_be_used_in_destructuring_patterns) + } + if propName != nil && ast.IsIdentifier(node.Name()) && ast.IsPartOfParameterDeclaration(node) && ast.NodeIsMissing(ast.GetContainingFunction(node).Body()) { // type F = ({a: string}) => void; // ^^^^^^ @@ -12693,6 +12698,11 @@ func (c *Checker) checkObjectLiteralDestructuringPropertyAssignment(node *ast.No property := properties[propertyIndex] if ast.IsPropertyAssignment(property) || ast.IsShorthandPropertyAssignment(property) { name := property.Name() + + if name != nil && ast.IsPrivateIdentifier(name) { + c.grammarErrorOnNode(name, diagnostics.Private_identifiers_cannot_be_used_in_destructuring_patterns) + } + exprType := c.getLiteralTypeFromPropertyName(name) if isTypeUsableAsPropertyName(exprType) { text := getPropertyNameFromType(exprType) diff --git a/tsc/internal/diagnostics/diagnosticMessages.json b/tsc/internal/diagnostics/diagnosticMessages.json index 17586e927d0ac..3d3e65c7256c9 100644 --- a/tsc/internal/diagnostics/diagnosticMessages.json +++ b/tsc/internal/diagnostics/diagnosticMessages.json @@ -8555,5 +8555,9 @@ "'{0}' is not a valid meta-property for keyword 'import'. Did you mean 'meta' or 'defer'?": { "category": "Error", "code": 18061 + }, + "Private identifiers cannot be used in destructuring patterns.": { + "category": "Error", + "code": 18064 } } diff --git a/tsc/internal/diagnostics/diagnostics_generated.go b/tsc/internal/diagnostics/diagnostics_generated.go index 96641c4d85818..83fdbf7c1b832 100644 --- a/tsc/internal/diagnostics/diagnostics_generated.go +++ b/tsc/internal/diagnostics/diagnostics_generated.go @@ -3762,6 +3762,8 @@ var Regular_expression_pattern_modifiers_are_only_available_when_targeting_0_or_ var Duplicate_named_capturing_groups_are_only_available_when_targeting_0_or_later = &Message{code: 18063, category: CategoryError, key: "Duplicate_named_capturing_groups_are_only_available_when_targeting_0_or_later_18063", text: "Duplicate named capturing groups are only available when targeting '{0}' or later."} +var Private_identifiers_cannot_be_used_in_destructuring_patterns = &Message{code: 18064, category: CategoryError, key: "Private_identifiers_cannot_be_used_in_destructuring_patterns_18064", text: "Private identifiers cannot be used in destructuring patterns."} + var X_nodenext_if_module_is_nodenext_node16_if_module_is_node16_or_node18_otherwise_bundler = &Message{code: 69010, category: CategoryMessage, key: "nodenext_if_module_is_nodenext_node16_if_module_is_node16_or_node18_otherwise_bundler_69010", text: "`nodenext` if `module` is `nodenext`; `node16` if `module` is `node16` or `node18`; otherwise, `bundler`."} var File_is_a_CommonJS_module_it_may_be_converted_to_an_ES_module = &Message{code: 80001, category: CategorySuggestion, key: "File_is_a_CommonJS_module_it_may_be_converted_to_an_ES_module_80001", text: "File is a CommonJS module; it may be converted to an ES module."} @@ -8172,6 +8174,8 @@ func keyToMessage(key Key) *Message { return Regular_expression_pattern_modifiers_are_only_available_when_targeting_0_or_later case "Duplicate_named_capturing_groups_are_only_available_when_targeting_0_or_later_18063": return Duplicate_named_capturing_groups_are_only_available_when_targeting_0_or_later + case "Private_identifiers_cannot_be_used_in_destructuring_patterns_18064": + return Private_identifiers_cannot_be_used_in_destructuring_patterns case "nodenext_if_module_is_nodenext_node16_if_module_is_node16_or_node18_otherwise_bundler_69010": return X_nodenext_if_module_is_nodenext_node16_if_module_is_node16_or_node18_otherwise_bundler case "File_is_a_CommonJS_module_it_may_be_converted_to_an_ES_module_80001": diff --git a/tsc/testdata/baselines/reference/conformance/privateNamesNotAllowedAsDestructuringPatterns.errors.txt b/tsc/testdata/baselines/reference/conformance/privateNamesNotAllowedAsDestructuringPatterns.errors.txt new file mode 100644 index 0000000000000..d02c0df9f747a --- /dev/null +++ b/tsc/testdata/baselines/reference/conformance/privateNamesNotAllowedAsDestructuringPatterns.errors.txt @@ -0,0 +1,18 @@ +privateNamesNotAllowedAsDestructuringPatterns.ts(4,17): error TS18064: Private identifiers cannot be used in destructuring patterns. +privateNamesNotAllowedAsDestructuringPatterns.ts(6,12): error TS18064: Private identifiers cannot be used in destructuring patterns. + + +==== privateNamesNotAllowedAsDestructuringPatterns.ts (2 errors) ==== + class A { + #foo = 1; + bar() { + const { #foo: foo } = this; + ~~~~ +!!! error TS18064: Private identifiers cannot be used in destructuring patterns. + let bar; + ({ #foo: bar } = this); + ~~~~ +!!! error TS18064: Private identifiers cannot be used in destructuring patterns. + } + } + \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/conformance/privateNamesNotAllowedAsDestructuringPatterns.js b/tsc/testdata/baselines/reference/conformance/privateNamesNotAllowedAsDestructuringPatterns.js new file mode 100644 index 0000000000000..fd967447d9d7f --- /dev/null +++ b/tsc/testdata/baselines/reference/conformance/privateNamesNotAllowedAsDestructuringPatterns.js @@ -0,0 +1,23 @@ +//// [tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsDestructuringPatterns.ts] //// + +//// [privateNamesNotAllowedAsDestructuringPatterns.ts] +class A { + #foo = 1; + bar() { + const { #foo: foo } = this; + let bar; + ({ #foo: bar } = this); + } +} + + +//// [privateNamesNotAllowedAsDestructuringPatterns.js] +"use strict"; +class A { + #foo = 1; + bar() { + const { #foo: foo } = this; + let bar; + ({ #foo: bar } = this); + } +} diff --git a/tsc/testdata/baselines/reference/conformance/privateNamesNotAllowedAsDestructuringPatterns.symbols b/tsc/testdata/baselines/reference/conformance/privateNamesNotAllowedAsDestructuringPatterns.symbols new file mode 100644 index 0000000000000..5cf75e09640d8 --- /dev/null +++ b/tsc/testdata/baselines/reference/conformance/privateNamesNotAllowedAsDestructuringPatterns.symbols @@ -0,0 +1,26 @@ +//// [tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsDestructuringPatterns.ts] //// + +=== privateNamesNotAllowedAsDestructuringPatterns.ts === +class A { +>A : Symbol(A, Decl(privateNamesNotAllowedAsDestructuringPatterns.ts, 0, 0)) + + #foo = 1; +>#foo : Symbol(A.#foo, Decl(privateNamesNotAllowedAsDestructuringPatterns.ts, 0, 9)) + + bar() { +>bar : Symbol(A.bar, Decl(privateNamesNotAllowedAsDestructuringPatterns.ts, 1, 13)) + + const { #foo: foo } = this; +>foo : Symbol(foo, Decl(privateNamesNotAllowedAsDestructuringPatterns.ts, 3, 15)) +>this : Symbol(A, Decl(privateNamesNotAllowedAsDestructuringPatterns.ts, 0, 0)) + + let bar; +>bar : Symbol(bar, Decl(privateNamesNotAllowedAsDestructuringPatterns.ts, 4, 11)) + + ({ #foo: bar } = this); +>#foo : Symbol(#foo, Decl(privateNamesNotAllowedAsDestructuringPatterns.ts, 5, 10)) +>bar : Symbol(bar, Decl(privateNamesNotAllowedAsDestructuringPatterns.ts, 4, 11)) +>this : Symbol(A, Decl(privateNamesNotAllowedAsDestructuringPatterns.ts, 0, 0)) + } +} + diff --git a/tsc/testdata/baselines/reference/conformance/privateNamesNotAllowedAsDestructuringPatterns.types b/tsc/testdata/baselines/reference/conformance/privateNamesNotAllowedAsDestructuringPatterns.types new file mode 100644 index 0000000000000..f0f1e1e75fe78 --- /dev/null +++ b/tsc/testdata/baselines/reference/conformance/privateNamesNotAllowedAsDestructuringPatterns.types @@ -0,0 +1,30 @@ +//// [tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsDestructuringPatterns.ts] //// + +=== privateNamesNotAllowedAsDestructuringPatterns.ts === +class A { +>A : A + + #foo = 1; +>#foo : number +>1 : 1 + + bar() { +>bar : () => void + + const { #foo: foo } = this; +>foo : never +>this : this + + let bar; +>bar : any + + ({ #foo: bar } = this); +>({ #foo: bar } = this) : this +>{ #foo: bar } = this : this +>{ #foo: bar } : { #foo: any; } +>#foo : any +>bar : any +>this : this + } +} + diff --git a/tsc/testdata/tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsDestructuringPatterns.ts b/tsc/testdata/tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsDestructuringPatterns.ts new file mode 100644 index 0000000000000..de36a0dcf983d --- /dev/null +++ b/tsc/testdata/tests/cases/conformance/classes/members/privateNames/privateNamesNotAllowedAsDestructuringPatterns.ts @@ -0,0 +1,10 @@ +// @target: es2022 + +class A { + #foo = 1; + bar() { + const { #foo: foo } = this; + let bar; + ({ #foo: bar } = this); + } +}