@@ -23917,6 +23917,9 @@ namespace ts {
23917
23917
case SyntaxKind.InstanceOfKeyword:
23918
23918
return narrowTypeByInstanceof(type, expr, assumeTrue);
23919
23919
case SyntaxKind.InKeyword:
23920
+ if (isPrivateIdentifier(expr.left)) {
23921
+ return narrowTypeByPrivateIdentifierInInExpression(type, expr, assumeTrue);
23922
+ }
23920
23923
const target = getReferenceCandidate(expr.right);
23921
23924
const leftType = getTypeOfNode(expr.left);
23922
23925
if (leftType.flags & TypeFlags.StringLiteral) {
@@ -23947,6 +23950,24 @@ namespace ts {
23947
23950
return type;
23948
23951
}
23949
23952
23953
+ function narrowTypeByPrivateIdentifierInInExpression(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type {
23954
+ const target = getReferenceCandidate(expr.right);
23955
+ if (!isMatchingReference(reference, target)) {
23956
+ return type;
23957
+ }
23958
+
23959
+ Debug.assertNode(expr.left, isPrivateIdentifier);
23960
+ const symbol = getSymbolForPrivateIdentifierExpression(expr.left);
23961
+ if (symbol === undefined) {
23962
+ return type;
23963
+ }
23964
+ const classSymbol = symbol.parent!;
23965
+ const targetType = hasStaticModifier(Debug.checkDefined(symbol.valueDeclaration, "should always have a declaration"))
23966
+ ? getTypeOfSymbol(classSymbol) as InterfaceType
23967
+ : getDeclaredTypeOfSymbol(classSymbol);
23968
+ return getNarrowedType(type, targetType, assumeTrue, isTypeDerivedFrom);
23969
+ }
23970
+
23950
23971
function narrowTypeByOptionalChainContainment(type: Type, operator: SyntaxKind, value: Expression, assumeTrue: boolean): Type {
23951
23972
// We are in a branch of obj?.foo === value (or any one of the other equality operators). We narrow obj as follows:
23952
23973
// When operator is === and type of value excludes undefined, null and undefined is removed from type of obj in true branch.
@@ -27790,6 +27811,40 @@ namespace ts {
27790
27811
}
27791
27812
}
27792
27813
27814
+ function checkGrammarPrivateIdentifierExpression(privId: PrivateIdentifier): boolean {
27815
+ if (!getContainingClass(privId)) {
27816
+ return grammarErrorOnNode(privId, Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies);
27817
+ }
27818
+ if (!isExpressionNode(privId)) {
27819
+ return grammarErrorOnNode(privId, Diagnostics.Private_identifiers_are_only_allowed_in_class_bodies_and_may_only_be_used_as_part_of_a_class_member_declaration_property_access_or_on_the_left_hand_side_of_an_in_expression);
27820
+ }
27821
+ if (!getSymbolForPrivateIdentifierExpression(privId)) {
27822
+ return grammarErrorOnNode(privId, Diagnostics.Cannot_find_name_0, idText(privId));
27823
+ }
27824
+ return false;
27825
+ }
27826
+
27827
+ function checkPrivateIdentifierExpression(privId: PrivateIdentifier): Type {
27828
+ checkGrammarPrivateIdentifierExpression(privId);
27829
+ const symbol = getSymbolForPrivateIdentifierExpression(privId);
27830
+ if (symbol) {
27831
+ markPropertyAsReferenced(symbol, /* nodeForCheckWriteOnly: */ undefined, /* isThisAccess: */ false);
27832
+ }
27833
+ return anyType;
27834
+ }
27835
+
27836
+ function getSymbolForPrivateIdentifierExpression(privId: PrivateIdentifier): Symbol | undefined {
27837
+ if (!isExpressionNode(privId)) {
27838
+ return undefined;
27839
+ }
27840
+
27841
+ const links = getNodeLinks(privId);
27842
+ if (links.resolvedSymbol === undefined) {
27843
+ links.resolvedSymbol = lookupSymbolForPrivateIdentifierDeclaration(privId.escapedText, privId);
27844
+ }
27845
+ return links.resolvedSymbol;
27846
+ }
27847
+
27793
27848
function getPrivateIdentifierPropertyOfType(leftType: Type, lexicallyScopedIdentifier: Symbol): Symbol | undefined {
27794
27849
return getPropertyOfType(leftType, lexicallyScopedIdentifier.escapedName);
27795
27850
}
@@ -32110,11 +32165,29 @@ namespace ts {
32110
32165
if (leftType === silentNeverType || rightType === silentNeverType) {
32111
32166
return silentNeverType;
32112
32167
}
32113
- leftType = checkNonNullType(leftType, left);
32168
+ if (isPrivateIdentifier(left)) {
32169
+ if (languageVersion < ScriptTarget.ESNext) {
32170
+ checkExternalEmitHelpers(left, ExternalEmitHelpers.ClassPrivateFieldIn);
32171
+ }
32172
+ // Unlike in 'checkPrivateIdentifierExpression' we now have access to the RHS type
32173
+ // which provides us with the opportunity to emit more detailed errors
32174
+ if (!getNodeLinks(left).resolvedSymbol && getContainingClass(left)) {
32175
+ const isUncheckedJS = isUncheckedJSSuggestion(left, rightType.symbol, /*excludeClasses*/ true);
32176
+ reportNonexistentProperty(left, rightType, isUncheckedJS);
32177
+ }
32178
+ }
32179
+ else {
32180
+ leftType = checkNonNullType(leftType, left);
32181
+ // TypeScript 1.0 spec (April 2014): 4.15.5
32182
+ // Require the left operand to be of type Any, the String primitive type, or the Number primitive type.
32183
+ if (!(allTypesAssignableToKind(leftType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbolLike) ||
32184
+ isTypeAssignableToKind(leftType, TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping | TypeFlags.TypeParameter))) {
32185
+ error(left, Diagnostics.The_left_hand_side_of_an_in_expression_must_be_a_private_identifier_or_of_type_any_string_number_or_symbol);
32186
+ }
32187
+ }
32114
32188
rightType = checkNonNullType(rightType, right);
32115
32189
// TypeScript 1.0 spec (April 2014): 4.15.5
32116
- // The in operator requires the left operand to be of type Any, the String primitive type, or the Number primitive type,
32117
- // and the right operand to be
32190
+ // The in operator requires the right operand to be
32118
32191
//
32119
32192
// 1. assignable to the non-primitive type,
32120
32193
// 2. an unconstrained type parameter,
@@ -32132,10 +32205,6 @@ namespace ts {
32132
32205
// unless *all* instantiations would result in an error.
32133
32206
//
32134
32207
// The result is always of the Boolean primitive type.
32135
- if (!(allTypesAssignableToKind(leftType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbolLike) ||
32136
- isTypeAssignableToKind(leftType, TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping | TypeFlags.TypeParameter))) {
32137
- error(left, Diagnostics.The_left_hand_side_of_an_in_expression_must_be_of_type_any_string_number_or_symbol);
32138
- }
32139
32208
const rightTypeConstraint = getConstraintOfType(rightType);
32140
32209
if (!allTypesAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive) ||
32141
32210
rightTypeConstraint && (
@@ -33517,6 +33586,8 @@ namespace ts {
33517
33586
switch (kind) {
33518
33587
case SyntaxKind.Identifier:
33519
33588
return checkIdentifier(node as Identifier, checkMode);
33589
+ case SyntaxKind.PrivateIdentifier:
33590
+ return checkPrivateIdentifierExpression(node as PrivateIdentifier);
33520
33591
case SyntaxKind.ThisKeyword:
33521
33592
return checkThisExpression(node);
33522
33593
case SyntaxKind.SuperKeyword:
@@ -40296,6 +40367,9 @@ namespace ts {
40296
40367
}
40297
40368
return result;
40298
40369
}
40370
+ else if (isPrivateIdentifier(name)) {
40371
+ return getSymbolForPrivateIdentifierExpression(name);
40372
+ }
40299
40373
else if (name.kind === SyntaxKind.PropertyAccessExpression || name.kind === SyntaxKind.QualifiedName) {
40300
40374
const links = getNodeLinks(name);
40301
40375
if (links.resolvedSymbol) {
@@ -41712,6 +41786,7 @@ namespace ts {
41712
41786
case ExternalEmitHelpers.MakeTemplateObject: return "__makeTemplateObject";
41713
41787
case ExternalEmitHelpers.ClassPrivateFieldGet: return "__classPrivateFieldGet";
41714
41788
case ExternalEmitHelpers.ClassPrivateFieldSet: return "__classPrivateFieldSet";
41789
+ case ExternalEmitHelpers.ClassPrivateFieldIn: return "__classPrivateFieldIn";
41715
41790
case ExternalEmitHelpers.CreateBinding: return "__createBinding";
41716
41791
default: return Debug.fail("Unrecognized helper");
41717
41792
}
0 commit comments