@@ -132,6 +132,7 @@ namespace ts {
132132 getDeclaredTypeOfSymbol,
133133 getPropertiesOfType,
134134 getPropertyOfType: (type, name) => getPropertyOfType(type, escapeLeadingUnderscores(name)),
135+ getPropertyForPrivateName,
135136 getTypeOfPropertyOfType: (type, name) => getTypeOfPropertyOfType(type, escapeLeadingUnderscores(name)),
136137 getIndexInfoOfType,
137138 getSignaturesOfType,
@@ -1606,8 +1607,8 @@ namespace ts {
16061607 }
16071608 }
16081609
1609- function diagnosticName(nameArg: __String | Identifier) {
1610- return isString(nameArg) ? unescapeLeadingUnderscores(nameArg as __String) : declarationNameToString(nameArg as Identifier);
1610+ function diagnosticName(nameArg: __String | Identifier | PrivateName ) {
1611+ return isString(nameArg) ? unescapeLeadingUnderscores(nameArg as __String) : declarationNameToString(nameArg as Identifier | PrivateName );
16111612 }
16121613
16131614 function isTypeParameterSymbolDeclaredInContainer(symbol: Symbol, container: Node) {
@@ -2796,15 +2797,16 @@ namespace ts {
27962797 return type;
27972798 }
27982799
2799- // A reserved member name starts with two underscores, but the third character cannot be an underscore
2800- // or the @ symbol . A third underscore indicates an escaped form of an identifer that started
2800+ // A reserved member name starts with two underscores, but the third character cannot be an underscore,
2801+ // @, or # . A third underscore indicates an escaped form of an identifer that started
28012802 // with at least two underscores. The @ character indicates that the name is denoted by a well known ES
2802- // Symbol instance.
2803+ // Symbol instance and the # indicates that the name is a PrivateName .
28032804 function isReservedMemberName(name: __String) {
28042805 return (name as string).charCodeAt(0) === CharacterCodes._ &&
28052806 (name as string).charCodeAt(1) === CharacterCodes._ &&
28062807 (name as string).charCodeAt(2) !== CharacterCodes._ &&
2807- (name as string).charCodeAt(2) !== CharacterCodes.at;
2808+ (name as string).charCodeAt(2) !== CharacterCodes.at &&
2809+ (name as string).charCodeAt(2) !== CharacterCodes.hash;
28082810 }
28092811
28102812 function getNamedMembers(members: SymbolTable): Symbol[] {
@@ -6511,7 +6513,7 @@ namespace ts {
65116513 */
65126514 function getPropertyNameFromType(type: StringLiteralType | NumberLiteralType | UniqueESSymbolType): __String {
65136515 if (type.flags & TypeFlags.UniqueESSymbol) {
6514- return (<UniqueESSymbolType> type).escapedName ;
6516+ return getPropertyNameForUniqueESSymbol( type.symbol) ;
65156517 }
65166518 if (type.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) {
65176519 return escapeLeadingUnderscores("" + (<StringLiteralType | NumberLiteralType>type).value);
@@ -9694,6 +9696,9 @@ namespace ts {
96949696 }
96959697
96969698 function getLiteralTypeFromPropertyName(name: PropertyName) {
9699+ if (isPrivateName(name)) {
9700+ return neverType;
9701+ }
96979702 return isIdentifier(name) ? getLiteralType(unescapeLeadingUnderscores(name.escapedText)) :
96989703 getRegularTypeOfLiteralType(isComputedPropertyName(name) ? checkComputedPropertyName(name) : checkExpression(name));
96999704 }
@@ -12929,23 +12934,44 @@ namespace ts {
1292912934 const unmatchedProperty = getUnmatchedProperty(source, target, requireOptionalProperties, /*matchDiscriminantProperties*/ false);
1293012935 if (unmatchedProperty) {
1293112936 if (reportErrors) {
12932- const props = arrayFrom(getUnmatchedProperties(source, target, requireOptionalProperties, /*matchDiscriminantProperties*/ false));
12933- if (!headMessage || (headMessage.code !== Diagnostics.Class_0_incorrectly_implements_interface_1.code &&
12934- headMessage.code !== Diagnostics.Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass.code)) {
12935- suppressNextError = true; // Retain top-level error for interface implementing issues, otherwise omit it
12936- }
12937- if (props.length === 1) {
12938- const propName = symbolToString(unmatchedProperty);
12939- reportError(Diagnostics.Property_0_is_missing_in_type_1_but_required_in_type_2, propName, typeToString(source), typeToString(target));
12940- if (length(unmatchedProperty.declarations)) {
12941- associateRelatedInfo(createDiagnosticForNode(unmatchedProperty.declarations[0], Diagnostics._0_is_declared_here, propName));
12937+ let hasReported = false;
12938+ // give specific error in case where private names have the same description
12939+ if (
12940+ unmatchedProperty.valueDeclaration
12941+ && isNamedDeclaration(unmatchedProperty.valueDeclaration)
12942+ && isPrivateName(unmatchedProperty.valueDeclaration.name)
12943+ && isClassDeclaration(source.symbol.valueDeclaration)
12944+ ) {
12945+ const privateNameDescription = unmatchedProperty.valueDeclaration.name.escapedText;
12946+ const symbolTableKey = getPropertyNameForPrivateNameDescription(source.symbol, privateNameDescription);
12947+ if (symbolTableKey && !!getPropertyOfType(source, symbolTableKey)) {
12948+ reportError(
12949+ 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,
12950+ diagnosticName(privateNameDescription),
12951+ diagnosticName(source.symbol.valueDeclaration.name || ("(anonymous)" as __String))
12952+ );
12953+ hasReported = true;
1294212954 }
1294312955 }
12944- else if (props.length > 5) { // arbitrary cutoff for too-long list form
12945- 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);
12946- }
12947- else {
12948- reportError(Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2, typeToString(source), typeToString(target), map(props, p => symbolToString(p)).join(", "));
12956+ if (!hasReported) {
12957+ const props = arrayFrom(getUnmatchedProperties(source, target, requireOptionalProperties, /*matchDiscriminantProperties*/ false));
12958+ if (!headMessage || (headMessage.code !== Diagnostics.Class_0_incorrectly_implements_interface_1.code &&
12959+ headMessage.code !== Diagnostics.Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass.code)) {
12960+ suppressNextError = true; // Retain top-level error for interface implementing issues, otherwise omit it
12961+ }
12962+ if (props.length === 1) {
12963+ const propName = symbolToString(unmatchedProperty);
12964+ reportError(Diagnostics.Property_0_is_missing_in_type_1_but_required_in_type_2, propName, typeToString(source), typeToString(target));
12965+ if (length(unmatchedProperty.declarations)) {
12966+ associateRelatedInfo(createDiagnosticForNode(unmatchedProperty.declarations[0], Diagnostics._0_is_declared_here, propName));
12967+ }
12968+ }
12969+ else if (props.length > 5) { // arbitrary cutoff for too-long list form
12970+ 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);
12971+ }
12972+ else {
12973+ reportError(Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2, typeToString(source), typeToString(target), map(props, p => symbolToString(p)).join(", "));
12974+ }
1294912975 }
1295012976 }
1295112977 return Ternary.False;
@@ -19383,6 +19409,48 @@ namespace ts {
1938319409 return checkPropertyAccessExpressionOrQualifiedName(node, node.left, node.right);
1938419410 }
1938519411
19412+ function getPropertyForPrivateName(apparentType: Type, leftType: Type, right: PrivateName, errorNode: Node | undefined): Symbol | undefined {
19413+ let classWithShadowedPrivateName;
19414+ let container = getContainingClass(right);
19415+ while (container) {
19416+ const symbolTableKey = getPropertyNameForPrivateNameDescription(container.symbol, right.escapedText);
19417+ if (symbolTableKey) {
19418+ const prop = getPropertyOfType(apparentType, symbolTableKey);
19419+ if (prop) {
19420+ if (classWithShadowedPrivateName) {
19421+ if (errorNode) {
19422+ error(
19423+ errorNode,
19424+ 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,
19425+ diagnosticName(right),
19426+ diagnosticName(classWithShadowedPrivateName.name || ("(anonymous)" as __String))
19427+ );
19428+ }
19429+ return undefined;
19430+ }
19431+ return prop;
19432+ }
19433+ else {
19434+ classWithShadowedPrivateName = container;
19435+ }
19436+ }
19437+ container = getContainingClass(container);
19438+ }
19439+ // If this isn't a case of shadowing, and the lhs has a property with the same
19440+ // private name description, then there is a privacy violation
19441+ if (leftType.symbol.members) {
19442+ const symbolTableKey = getPropertyNameForPrivateNameDescription(leftType.symbol, right.escapedText);
19443+ const prop = getPropertyOfType(apparentType, symbolTableKey);
19444+ if (prop) {
19445+ if (errorNode) {
19446+ error(right, Diagnostics.Property_0_is_not_accessible_outside_class_1_because_it_has_a_private_name, symbolToString(prop), typeToString(getDeclaringClass(prop)!));
19447+ }
19448+ }
19449+ }
19450+ // not found
19451+ return undefined;
19452+ }
19453+
1938619454 function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier | PrivateName) {
1938719455 let propType: Type;
1938819456 const leftType = checkNonNullExpression(left);
@@ -19395,7 +19463,7 @@ namespace ts {
1939519463 return apparentType;
1939619464 }
1939719465 const assignmentKind = getAssignmentTargetKind(node);
19398- const prop = getPropertyOfType(apparentType, right.escapedText);
19466+ const prop = isPrivateName(right) ? getPropertyForPrivateName(apparentType, leftType, right, /* errorNode */ right) : getPropertyOfType(apparentType, right.escapedText);
1939919467 if (isIdentifier(left) && parentSymbol && !(prop && isConstEnumOrConstEnumOnlyModule(prop))) {
1940019468 markAliasReferenced(parentSymbol, node);
1940119469 }
@@ -22384,6 +22452,9 @@ namespace ts {
2238422452 error(expr, Diagnostics.The_operand_of_a_delete_operator_must_be_a_property_reference);
2238522453 return booleanType;
2238622454 }
22455+ if (expr.kind === SyntaxKind.PropertyAccessExpression && isPrivateName((expr as PropertyAccessExpression).name)) {
22456+ error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_private_name);
22457+ }
2238722458 const links = getNodeLinks(expr);
2238822459 const symbol = getExportSymbolOfValueSymbolIfExported(links.resolvedSymbol);
2238922460 if (symbol && isReadonlySymbol(symbol)) {
@@ -23592,9 +23663,6 @@ namespace ts {
2359223663 checkGrammarDecoratorsAndModifiers(node);
2359323664
2359423665 checkVariableLikeDeclaration(node);
23595- if (node.name && isIdentifier(node.name) && node.name.originalKeywordKind === SyntaxKind.PrivateName) {
23596- error(node, Diagnostics.Private_names_cannot_be_used_as_parameters);
23597- }
2359823666 const func = getContainingFunction(node)!;
2359923667 if (hasModifier(node, ModifierFlags.ParameterPropertyModifier)) {
2360023668 if (!(func.kind === SyntaxKind.Constructor && nodeIsPresent(func.body))) {
@@ -30350,6 +30418,9 @@ namespace ts {
3035030418 else if (node.kind === SyntaxKind.Parameter && (flags & ModifierFlags.ParameterPropertyModifier) && (<ParameterDeclaration>node).dotDotDotToken) {
3035130419 return grammarErrorOnNode(node, Diagnostics.A_parameter_property_cannot_be_declared_using_a_rest_parameter);
3035230420 }
30421+ else if (isNamedDeclaration(node) && (flags & ModifierFlags.AccessibilityModifier) && node.name.kind === SyntaxKind.PrivateName) {
30422+ return grammarErrorOnNode(node, Diagnostics.Accessibility_modifiers_cannot_be_used_with_private_names);
30423+ }
3035330424 if (flags & ModifierFlags.Async) {
3035430425 return checkGrammarAsyncModifier(node, lastAsync!);
3035530426 }
@@ -30747,6 +30818,10 @@ namespace ts {
3074730818 return grammarErrorOnNode(prop.equalsToken!, Diagnostics.can_only_be_used_in_an_object_literal_property_inside_a_destructuring_assignment);
3074830819 }
3074930820
30821+ if (name.kind === SyntaxKind.PrivateName) {
30822+ return grammarErrorOnNode(name, Diagnostics.Private_names_are_not_allowed_outside_class_bodies);
30823+ }
30824+
3075030825 // Modifiers are never allowed on properties except for 'async' on a method declaration
3075130826 if (prop.modifiers) {
3075230827 for (const mod of prop.modifiers!) { // TODO: GH#19955
@@ -31188,10 +31263,6 @@ namespace ts {
3118831263 checkESModuleMarker(node.name);
3118931264 }
3119031265
31191- if (isIdentifier(node.name) && node.name.originalKeywordKind === SyntaxKind.PrivateName) {
31192- return grammarErrorOnNode(node.name, Diagnostics.Private_names_are_not_allowed_in_variable_declarations);
31193- }
31194-
3119531266 const checkLetConstNames = (isLet(node) || isVarConst(node));
3119631267
3119731268 // 1. LexicalDeclaration : LetOrConst BindingList ;
0 commit comments