@@ -132,6 +132,7 @@ namespace ts {
132
132
getDeclaredTypeOfSymbol,
133
133
getPropertiesOfType,
134
134
getPropertyOfType: (type, name) => getPropertyOfType(type, escapeLeadingUnderscores(name)),
135
+ getPropertyForPrivateName,
135
136
getTypeOfPropertyOfType: (type, name) => getTypeOfPropertyOfType(type, escapeLeadingUnderscores(name)),
136
137
getIndexInfoOfType,
137
138
getSignaturesOfType,
@@ -1605,8 +1606,8 @@ namespace ts {
1605
1606
}
1606
1607
}
1607
1608
1608
- function diagnosticName(nameArg: __String | Identifier) {
1609
- return isString(nameArg) ? unescapeLeadingUnderscores(nameArg as __String) : declarationNameToString(nameArg as Identifier);
1609
+ function diagnosticName(nameArg: __String | Identifier | PrivateName ) {
1610
+ return isString(nameArg) ? unescapeLeadingUnderscores(nameArg as __String) : declarationNameToString(nameArg as Identifier | PrivateName );
1610
1611
}
1611
1612
1612
1613
function isTypeParameterSymbolDeclaredInContainer(symbol: Symbol, container: Node) {
@@ -2795,15 +2796,16 @@ namespace ts {
2795
2796
return type;
2796
2797
}
2797
2798
2798
- // A reserved member name starts with two underscores, but the third character cannot be an underscore
2799
- // or the @ symbol . A third underscore indicates an escaped form of an identifer that started
2799
+ // A reserved member name starts with two underscores, but the third character cannot be an underscore,
2800
+ // @, or # . A third underscore indicates an escaped form of an identifer that started
2800
2801
// with at least two underscores. The @ character indicates that the name is denoted by a well known ES
2801
- // Symbol instance.
2802
+ // Symbol instance and the # indicates that the name is a PrivateName .
2802
2803
function isReservedMemberName(name: __String) {
2803
2804
return (name as string).charCodeAt(0) === CharacterCodes._ &&
2804
2805
(name as string).charCodeAt(1) === CharacterCodes._ &&
2805
2806
(name as string).charCodeAt(2) !== CharacterCodes._ &&
2806
- (name as string).charCodeAt(2) !== CharacterCodes.at;
2807
+ (name as string).charCodeAt(2) !== CharacterCodes.at &&
2808
+ (name as string).charCodeAt(2) !== CharacterCodes.hash;
2807
2809
}
2808
2810
2809
2811
function getNamedMembers(members: SymbolTable): Symbol[] {
@@ -6510,7 +6512,7 @@ namespace ts {
6510
6512
*/
6511
6513
function getPropertyNameFromType(type: StringLiteralType | NumberLiteralType | UniqueESSymbolType): __String {
6512
6514
if (type.flags & TypeFlags.UniqueESSymbol) {
6513
- return (<UniqueESSymbolType> type).escapedName ;
6515
+ return getPropertyNameForUniqueESSymbol( type.symbol) ;
6514
6516
}
6515
6517
if (type.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) {
6516
6518
return escapeLeadingUnderscores("" + (<StringLiteralType | NumberLiteralType>type).value);
@@ -9733,6 +9735,9 @@ namespace ts {
9733
9735
}
9734
9736
9735
9737
function getLiteralTypeFromPropertyName(name: PropertyName) {
9738
+ if (isPrivateName(name)) {
9739
+ return neverType;
9740
+ }
9736
9741
return isIdentifier(name) ? getLiteralType(unescapeLeadingUnderscores(name.escapedText)) :
9737
9742
getRegularTypeOfLiteralType(isComputedPropertyName(name) ? checkComputedPropertyName(name) : checkExpression(name));
9738
9743
}
@@ -13008,23 +13013,44 @@ namespace ts {
13008
13013
const unmatchedProperty = getUnmatchedProperty(source, target, requireOptionalProperties, /*matchDiscriminantProperties*/ false);
13009
13014
if (unmatchedProperty) {
13010
13015
if (reportErrors) {
13011
- const props = arrayFrom(getUnmatchedProperties(source, target, requireOptionalProperties, /*matchDiscriminantProperties*/ false));
13012
- if (!headMessage || (headMessage.code !== Diagnostics.Class_0_incorrectly_implements_interface_1.code &&
13013
- headMessage.code !== Diagnostics.Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass.code)) {
13014
- suppressNextError = true; // Retain top-level error for interface implementing issues, otherwise omit it
13015
- }
13016
- if (props.length === 1) {
13017
- const propName = symbolToString(unmatchedProperty);
13018
- reportError(Diagnostics.Property_0_is_missing_in_type_1_but_required_in_type_2, propName, typeToString(source), typeToString(target));
13019
- if (length(unmatchedProperty.declarations)) {
13020
- associateRelatedInfo(createDiagnosticForNode(unmatchedProperty.declarations[0], Diagnostics._0_is_declared_here, propName));
13016
+ let hasReported = false;
13017
+ // give specific error in case where private names have the same description
13018
+ if (
13019
+ unmatchedProperty.valueDeclaration
13020
+ && isNamedDeclaration(unmatchedProperty.valueDeclaration)
13021
+ && isPrivateName(unmatchedProperty.valueDeclaration.name)
13022
+ && isClassDeclaration(source.symbol.valueDeclaration)
13023
+ ) {
13024
+ const privateNameDescription = unmatchedProperty.valueDeclaration.name.escapedText;
13025
+ const symbolTableKey = getPropertyNameForPrivateNameDescription(source.symbol, privateNameDescription);
13026
+ if (symbolTableKey && !!getPropertyOfType(source, symbolTableKey)) {
13027
+ reportError(
13028
+ Diagnostics.Property_0_is_missing_in_type_1_While_type_1_has_a_private_member_with_the_same_spelling_its_declaration_and_accessibility_are_distinct,
13029
+ diagnosticName(privateNameDescription),
13030
+ diagnosticName(source.symbol.valueDeclaration.name || ("(anonymous)" as __String))
13031
+ );
13032
+ hasReported = true;
13021
13033
}
13022
13034
}
13023
- else if (props.length > 5) { // arbitrary cutoff for too-long list form
13024
- reportError(Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2_and_3_more, typeToString(source), typeToString(target), map(props.slice(0, 4), p => symbolToString(p)).join(", "), props.length - 4);
13025
- }
13026
- else {
13027
- reportError(Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2, typeToString(source), typeToString(target), map(props, p => symbolToString(p)).join(", "));
13035
+ if (!hasReported) {
13036
+ const props = arrayFrom(getUnmatchedProperties(source, target, requireOptionalProperties, /*matchDiscriminantProperties*/ false));
13037
+ if (!headMessage || (headMessage.code !== Diagnostics.Class_0_incorrectly_implements_interface_1.code &&
13038
+ headMessage.code !== Diagnostics.Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass.code)) {
13039
+ suppressNextError = true; // Retain top-level error for interface implementing issues, otherwise omit it
13040
+ }
13041
+ if (props.length === 1) {
13042
+ const propName = symbolToString(unmatchedProperty);
13043
+ reportError(Diagnostics.Property_0_is_missing_in_type_1_but_required_in_type_2, propName, typeToString(source), typeToString(target));
13044
+ if (length(unmatchedProperty.declarations)) {
13045
+ associateRelatedInfo(createDiagnosticForNode(unmatchedProperty.declarations[0], Diagnostics._0_is_declared_here, propName));
13046
+ }
13047
+ }
13048
+ else if (props.length > 5) { // arbitrary cutoff for too-long list form
13049
+ reportError(Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2_and_3_more, typeToString(source), typeToString(target), map(props.slice(0, 4), p => symbolToString(p)).join(", "), props.length - 4);
13050
+ }
13051
+ else {
13052
+ reportError(Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2, typeToString(source), typeToString(target), map(props, p => symbolToString(p)).join(", "));
13053
+ }
13028
13054
}
13029
13055
}
13030
13056
return Ternary.False;
@@ -19493,6 +19519,48 @@ namespace ts {
19493
19519
return checkPropertyAccessExpressionOrQualifiedName(node, node.left, node.right);
19494
19520
}
19495
19521
19522
+ function getPropertyForPrivateName(apparentType: Type, leftType: Type, right: PrivateName, errorNode: Node | undefined): Symbol | undefined {
19523
+ let classWithShadowedPrivateName;
19524
+ let container = getContainingClass(right);
19525
+ while (container) {
19526
+ const symbolTableKey = getPropertyNameForPrivateNameDescription(container.symbol, right.escapedText);
19527
+ if (symbolTableKey) {
19528
+ const prop = getPropertyOfType(apparentType, symbolTableKey);
19529
+ if (prop) {
19530
+ if (classWithShadowedPrivateName) {
19531
+ if (errorNode) {
19532
+ error(
19533
+ errorNode,
19534
+ Diagnostics.This_usage_of_0_refers_to_the_private_member_declared_in_its_enclosing_class_While_type_1_has_a_private_member_with_the_same_spelling_its_declaration_and_accessibility_are_distinct,
19535
+ diagnosticName(right),
19536
+ diagnosticName(classWithShadowedPrivateName.name || ("(anonymous)" as __String))
19537
+ );
19538
+ }
19539
+ return undefined;
19540
+ }
19541
+ return prop;
19542
+ }
19543
+ else {
19544
+ classWithShadowedPrivateName = container;
19545
+ }
19546
+ }
19547
+ container = getContainingClass(container);
19548
+ }
19549
+ // If this isn't a case of shadowing, and the lhs has a property with the same
19550
+ // private name description, then there is a privacy violation
19551
+ if (leftType.symbol.members) {
19552
+ const symbolTableKey = getPropertyNameForPrivateNameDescription(leftType.symbol, right.escapedText);
19553
+ const prop = getPropertyOfType(apparentType, symbolTableKey);
19554
+ if (prop) {
19555
+ if (errorNode) {
19556
+ error(right, Diagnostics.Property_0_is_not_accessible_outside_class_1_because_it_has_a_private_name, symbolToString(prop), typeToString(getDeclaringClass(prop)!));
19557
+ }
19558
+ }
19559
+ }
19560
+ // not found
19561
+ return undefined;
19562
+ }
19563
+
19496
19564
function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier | PrivateName) {
19497
19565
let propType: Type;
19498
19566
const leftType = checkNonNullExpression(left);
@@ -19505,7 +19573,7 @@ namespace ts {
19505
19573
return apparentType;
19506
19574
}
19507
19575
const assignmentKind = getAssignmentTargetKind(node);
19508
- const prop = getPropertyOfType(apparentType, right.escapedText);
19576
+ const prop = isPrivateName(right) ? getPropertyForPrivateName(apparentType, leftType, right, /* errorNode */ right) : getPropertyOfType(apparentType, right.escapedText);
19509
19577
if (isIdentifier(left) && parentSymbol && !(prop && isConstEnumOrConstEnumOnlyModule(prop))) {
19510
19578
markAliasReferenced(parentSymbol, node);
19511
19579
}
@@ -22522,6 +22590,9 @@ namespace ts {
22522
22590
error(expr, Diagnostics.The_operand_of_a_delete_operator_must_be_a_property_reference);
22523
22591
return booleanType;
22524
22592
}
22593
+ if (expr.kind === SyntaxKind.PropertyAccessExpression && isPrivateName((expr as PropertyAccessExpression).name)) {
22594
+ error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_private_name);
22595
+ }
22525
22596
const links = getNodeLinks(expr);
22526
22597
const symbol = getExportSymbolOfValueSymbolIfExported(links.resolvedSymbol);
22527
22598
if (symbol && isReadonlySymbol(symbol)) {
@@ -23833,9 +23904,6 @@ namespace ts {
23833
23904
checkGrammarDecoratorsAndModifiers(node);
23834
23905
23835
23906
checkVariableLikeDeclaration(node);
23836
- if (node.name && isIdentifier(node.name) && node.name.originalKeywordKind === SyntaxKind.PrivateName) {
23837
- error(node, Diagnostics.Private_names_cannot_be_used_as_parameters);
23838
- }
23839
23907
const func = getContainingFunction(node)!;
23840
23908
if (hasModifier(node, ModifierFlags.ParameterPropertyModifier)) {
23841
23909
if (!(func.kind === SyntaxKind.Constructor && nodeIsPresent(func.body))) {
@@ -30591,6 +30659,9 @@ namespace ts {
30591
30659
else if (node.kind === SyntaxKind.Parameter && (flags & ModifierFlags.ParameterPropertyModifier) && (<ParameterDeclaration>node).dotDotDotToken) {
30592
30660
return grammarErrorOnNode(node, Diagnostics.A_parameter_property_cannot_be_declared_using_a_rest_parameter);
30593
30661
}
30662
+ else if (isNamedDeclaration(node) && (flags & ModifierFlags.AccessibilityModifier) && node.name.kind === SyntaxKind.PrivateName) {
30663
+ return grammarErrorOnNode(node, Diagnostics.Accessibility_modifiers_cannot_be_used_with_private_names);
30664
+ }
30594
30665
if (flags & ModifierFlags.Async) {
30595
30666
return checkGrammarAsyncModifier(node, lastAsync!);
30596
30667
}
@@ -30988,6 +31059,10 @@ namespace ts {
30988
31059
return grammarErrorOnNode(prop.equalsToken!, Diagnostics.can_only_be_used_in_an_object_literal_property_inside_a_destructuring_assignment);
30989
31060
}
30990
31061
31062
+ if (name.kind === SyntaxKind.PrivateName) {
31063
+ return grammarErrorOnNode(name, Diagnostics.Private_names_are_not_allowed_outside_class_bodies);
31064
+ }
31065
+
30991
31066
// Modifiers are never allowed on properties except for 'async' on a method declaration
30992
31067
if (prop.modifiers) {
30993
31068
for (const mod of prop.modifiers!) { // TODO: GH#19955
@@ -31429,10 +31504,6 @@ namespace ts {
31429
31504
checkESModuleMarker(node.name);
31430
31505
}
31431
31506
31432
- if (isIdentifier(node.name) && node.name.originalKeywordKind === SyntaxKind.PrivateName) {
31433
- return grammarErrorOnNode(node.name, Diagnostics.Private_names_are_not_allowed_in_variable_declarations);
31434
- }
31435
-
31436
31507
const checkLetConstNames = (isLet(node) || isVarConst(node));
31437
31508
31438
31509
// 1. LexicalDeclaration : LetOrConst BindingList ;
0 commit comments