diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 78bca28c26b15..7f902330f8286 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -879,6 +879,8 @@ namespace ts { return (expr as PrefixUnaryExpression).operator === SyntaxKind.ExclamationToken && isNarrowingExpression((expr as PrefixUnaryExpression).operand); case SyntaxKind.TypeOfExpression: return isNarrowingExpression((expr as TypeOfExpression).expression); + case SyntaxKind.PrivateIdentifierInInExpression: + return isNarrowingExpression((expr as PrivateIdentifierInInExpression).expression); } return false; } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 44cd5f0608345..4b4e35c826cb9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23590,6 +23590,32 @@ namespace ts { return type; } + function narrowTypeByPrivateIdentifierInInExpression(type: Type, expr: PrivateIdentifierInInExpression, assumeTrue: boolean): Type { + const target = getReferenceCandidate(expr.expression); + if (!isMatchingReference(reference, target)) { + return type; + } + + const privateId = expr.name; + const symbol = lookupSymbolForPrivateIdentifierDeclaration(privateId.escapedText, privateId); + if (symbol === undefined) { + return type; + } + const classSymbol = symbol.parent!; + const classType = getTypeOfSymbol(classSymbol) as InterfaceType; + const classDecl = symbol.valueDeclaration; + Debug.assert(classDecl, "should always have a declaration"); + let targetType: Type; + if (hasStaticModifier(classDecl)) { + targetType = classType; + } + else { + const classInstanceType = getDeclaredTypeOfSymbol(classSymbol); + targetType = classInstanceType; + } + return getNarrowedType(type, targetType, assumeTrue, isTypeDerivedFrom); + } + function narrowTypeByOptionalChainContainment(type: Type, operator: SyntaxKind, value: Expression, assumeTrue: boolean): Type { // We are in a branch of obj?.foo === value (or any one of the other equality operators). We narrow obj as follows: // When operator is === and type of value excludes undefined, null and undefined is removed from type of obj in true branch. @@ -24022,6 +24048,8 @@ namespace ts { return narrowType(type, (expr as ParenthesizedExpression | NonNullExpression).expression, assumeTrue); case SyntaxKind.BinaryExpression: return narrowTypeByBinaryExpression(type, expr as BinaryExpression, assumeTrue); + case SyntaxKind.PrivateIdentifierInInExpression: + return narrowTypeByPrivateIdentifierInInExpression(type, expr as PrivateIdentifierInInExpression, assumeTrue); case SyntaxKind.PrefixUnaryExpression: if ((expr as PrefixUnaryExpression).operator === SyntaxKind.ExclamationToken) { return narrowType(type, (expr as PrefixUnaryExpression).operand, !assumeTrue); @@ -27726,6 +27754,7 @@ namespace ts { } function getSuggestedSymbolForNonexistentProperty(name: Identifier | PrivateIdentifier | string, containingType: Type): Symbol | undefined { + const originalName = name; let props = getPropertiesOfType(containingType); if (typeof name !== "string") { const parent = name.parent; @@ -27734,7 +27763,23 @@ namespace ts { } name = idText(name); } - return getSpellingSuggestionForName(name, props, SymbolFlags.Value); + const suggestion = getSpellingSuggestionForName(name, props, SymbolFlags.Value); + if (suggestion) { + return suggestion; + } + // If we have `#typo in expr` then we can still look up potential privateIdentifiers from the surrounding classes + if (typeof originalName !== "string" && isPrivateIdentifierInInExpression(originalName.parent)) { + const privateIdentifiers: Symbol[] = []; + forEachEnclosingClass(originalName, (klass: ClassLikeDeclaration) => { + forEach(klass.members, member => { + if (isPrivateIdentifierClassElementDeclaration(member)) { + privateIdentifiers.push(member.symbol); + } + }); + }); + return getSpellingSuggestionForName(name, privateIdentifiers, SymbolFlags.Value); + } + return undefined; } function getSuggestedSymbolForNonexistentJSXAttribute(name: Identifier | PrivateIdentifier | string, containingType: Type): Symbol | undefined { @@ -31494,6 +31539,11 @@ namespace ts { isTypeAssignableToKind(leftType, TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping | TypeFlags.TypeParameter))) { error(left, Diagnostics.The_left_hand_side_of_an_in_expression_must_be_of_type_any_string_number_or_symbol); } + checkInExpressionRHS(right, rightType); + return booleanType; + } + + function checkInExpressionRHS(right: Expression, rightType: Type) { const rightTypeConstraint = getConstraintOfType(rightType); if (!allTypesAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive) || rightTypeConstraint && ( @@ -31503,7 +31553,6 @@ namespace ts { ) { error(right, Diagnostics.The_right_hand_side_of_an_in_expression_must_not_be_a_primitive); } - return booleanType; } function checkObjectLiteralAssignment(node: ObjectLiteralExpression, sourceType: Type, rightIsThis?: boolean): Type { @@ -31740,6 +31789,40 @@ namespace ts { return (target.flags & TypeFlags.Nullable) !== 0 || isTypeComparableTo(source, target); } + function checkPrivateIdentifierInInExpression(node: PrivateIdentifierInInExpression, checkMode?: CheckMode) { + const privateId = node.name; + const exp = node.expression; + let rightType = checkExpression(exp, checkMode); + + const lexicallyScopedSymbol = lookupSymbolForPrivateIdentifierDeclaration(privateId.escapedText, privateId); + if (lexicallyScopedSymbol === undefined) { + if (!getContainingClass(node)) { + error(privateId, Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies); + } + else { + const suggestion = getSuggestedSymbolForNonexistentProperty(privateId, rightType); + if (suggestion) { + const suggestedName = symbolName(suggestion); + error(privateId, Diagnostics.Cannot_find_name_0_Did_you_mean_1, diagnosticName(privateId), suggestedName); + } + else { + error(privateId, Diagnostics.Cannot_find_name_0, diagnosticName(privateId)); + } + } + return anyType; + } + + markPropertyAsReferenced(lexicallyScopedSymbol, /* nodeForCheckWriteOnly: */ undefined, /* isThisAccess: */ false); + getNodeLinks(node).resolvedSymbol = lexicallyScopedSymbol; + + if (rightType === silentNeverType) { + return silentNeverType; + } + rightType = checkNonNullType(rightType, exp); + checkInExpressionRHS(exp, rightType); + return booleanType; + } + function createCheckBinaryExpression() { interface WorkArea { readonly checkMode: CheckMode | undefined; @@ -32921,6 +33004,8 @@ namespace ts { return checkPostfixUnaryExpression(node as PostfixUnaryExpression); case SyntaxKind.BinaryExpression: return checkBinaryExpression(node as BinaryExpression, checkMode); + case SyntaxKind.PrivateIdentifierInInExpression: + return checkPrivateIdentifierInInExpression(node as PrivateIdentifierInInExpression, checkMode); case SyntaxKind.ConditionalExpression: return checkConditionalExpression(node as ConditionalExpression, checkMode); case SyntaxKind.SpreadElement: @@ -39416,6 +39501,15 @@ namespace ts { return resolveEntityName(name as Identifier, /*meaning*/ SymbolFlags.FunctionScopedVariable); } + if (isPrivateIdentifier(name) && isPrivateIdentifierInInExpression(name.parent)) { + const links = getNodeLinks(name.parent); + if (links.resolvedSymbol) { + return links.resolvedSymbol; + } + checkPrivateIdentifierInInExpression(name.parent); + return links.resolvedSymbol; + } + return undefined; } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index fc945a4cac70f..de343e520ec0d 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1716,6 +1716,8 @@ namespace ts { return emitPostfixUnaryExpression(node as PostfixUnaryExpression); case SyntaxKind.BinaryExpression: return emitBinaryExpression(node as BinaryExpression); + case SyntaxKind.PrivateIdentifierInInExpression: + return emitPrivateIdentifierInInExpression(node as PrivateIdentifierInInExpression); case SyntaxKind.ConditionalExpression: return emitConditionalExpression(node as ConditionalExpression); case SyntaxKind.TemplateExpression: @@ -2690,6 +2692,24 @@ namespace ts { } } + function emitPrivateIdentifierInInExpression(node: PrivateIdentifierInInExpression) { + const linesBeforeIn = getLinesBetweenNodes(node, node.name, node.inToken); + const linesAfterIn = getLinesBetweenNodes(node, node.inToken, node.expression); + + emitLeadingCommentsOfPosition(node.name.pos); + emitPrivateIdentifier(node.name); + emitTrailingCommentsOfPosition(node.name.end); + + writeLinesAndIndent(linesBeforeIn, /*writeSpaceIfNotIndenting*/ true); + emitLeadingCommentsOfPosition(node.inToken.pos); + writeTokenNode(node.inToken, writeKeyword); + emitTrailingCommentsOfPosition(node.inToken.end, /*prefixSpace*/ true); + writeLinesAndIndent(linesAfterIn, /*writeSpaceIfNotIndenting*/ true); + + emit(node.expression); + decreaseIndentIf(linesBeforeIn, linesAfterIn); + } + function emitConditionalExpression(node: ConditionalExpression) { const linesBeforeQuestion = getLinesBetweenNodes(node, node.condition, node.questionToken); const linesAfterQuestion = getLinesBetweenNodes(node, node.questionToken, node.whenTrue); diff --git a/src/compiler/factory/emitHelpers.ts b/src/compiler/factory/emitHelpers.ts index f3e0004efd407..9df1d4126cd43 100644 --- a/src/compiler/factory/emitHelpers.ts +++ b/src/compiler/factory/emitHelpers.ts @@ -34,6 +34,7 @@ namespace ts { // Class Fields Helpers createClassPrivateFieldGetHelper(receiver: Expression, state: Identifier, kind: PrivateIdentifierKind, f: Identifier | undefined): Expression; createClassPrivateFieldSetHelper(receiver: Expression, state: Identifier, value: Expression, kind: PrivateIdentifierKind, f: Identifier | undefined): Expression; + createClassPrivateFieldInHelper(receiver: Expression, state: Identifier): Expression; } export function createEmitHelperFactory(context: TransformationContext): EmitHelperFactory { @@ -72,6 +73,7 @@ namespace ts { // Class Fields Helpers createClassPrivateFieldGetHelper, createClassPrivateFieldSetHelper, + createClassPrivateFieldInHelper }; /** @@ -392,6 +394,10 @@ namespace ts { return factory.createCallExpression(getUnscopedHelperName("__classPrivateFieldSet"), /*typeArguments*/ undefined, args); } + function createClassPrivateFieldInHelper(receiver: Expression, state: Identifier) { + context.requestEmitHelper(classPrivateFieldInHelper); + return factory.createCallExpression(getUnscopedHelperName("__classPrivateFieldIn"), /* typeArguments*/ undefined, [receiver, state]); + } } /* @internal */ @@ -954,6 +960,17 @@ namespace ts { };` }; + export const classPrivateFieldInHelper: UnscopedEmitHelper = { + name: "typescript:classPrivateFieldIn", + importName: "__classPrivateFieldIn", + scoped: false, + text: ` + var __classPrivateFieldIn = (this && this.__classPrivateFieldIn) || function(receiver, state) { + if (receiver === null || (typeof receiver !== "object" && typeof receiver !== "function")) throw new TypeError("Cannot use 'in' operator on non-object"); + return typeof state === "function" ? receiver === state : state.has(receiver); + };` + }; + let allUnscopedEmitHelpers: ReadonlyESMap | undefined; export function getAllUnscopedEmitHelpers() { @@ -979,6 +996,7 @@ namespace ts { exportStarHelper, classPrivateFieldGetHelper, classPrivateFieldSetHelper, + classPrivateFieldInHelper, createBindingHelper, setModuleDefaultHelper ], helper => helper.name)); diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index 4b75321a84ee2..63341684535ca 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -443,6 +443,8 @@ namespace ts { createMergeDeclarationMarker, createSyntheticReferenceExpression, updateSyntheticReferenceExpression, + createPrivateIdentifierInInExpression, + updatePrivateIdentifierInInExpression, cloneNode, // Lazily load factory methods for common operator factories and utilities @@ -3066,6 +3068,34 @@ namespace ts { : node; } + // @api + function createPrivateIdentifierInInExpression(name: PrivateIdentifier, inToken: Token, expression: Expression) { + const node = createBaseExpression(SyntaxKind.PrivateIdentifierInInExpression); + node.name = name; + node.inToken = inToken; + node.expression = expression; + node.transformFlags |= + propagateChildFlags(node.name) | + propagateChildFlags(node.inToken) | + propagateChildFlags(node.expression) | + TransformFlags.ContainsESNext; + return node; + } + + // @api + function updatePrivateIdentifierInInExpression( + node: PrivateIdentifierInInExpression, + name: PrivateIdentifier, + inToken: Token, + expression: Expression + ): PrivateIdentifierInInExpression { + return node.name !== name + || node.inToken !== inToken + || node.expression !== expression + ? update(createPrivateIdentifierInInExpression(name, inToken, expression), node) + : node; + } + // // Misc // diff --git a/src/compiler/factory/nodeTests.ts b/src/compiler/factory/nodeTests.ts index fbe8a1ccd69fa..8b42bf3f09e06 100644 --- a/src/compiler/factory/nodeTests.ts +++ b/src/compiler/factory/nodeTests.ts @@ -87,6 +87,11 @@ namespace ts { return node.kind === SyntaxKind.EqualsGreaterThanToken; } + /*@internal*/ + export function isInKeyword(node: Node): node is InKeyword { + return node.kind === SyntaxKind.InKeyword; + } + // Identifiers export function isIdentifier(node: Node): node is Identifier { @@ -444,6 +449,10 @@ namespace ts { return node.kind === SyntaxKind.CommaListExpression; } + export function isPrivateIdentifierInInExpression(node: Node): node is PrivateIdentifierInInExpression { + return node.kind === SyntaxKind.PrivateIdentifierInInExpression; + } + // Misc export function isTemplateSpan(node: Node): node is TemplateSpan { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 8a6743090f9dc..2488f514a9f3d 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -442,6 +442,9 @@ namespace ts { return visitNodes(cbNode, cbNodes, node.decorators); case SyntaxKind.CommaListExpression: return visitNodes(cbNode, cbNodes, (node as CommaListExpression).elements); + case SyntaxKind.PrivateIdentifierInInExpression: + return visitNode(cbNode, (node as PrivateIdentifierInInExpression).name) || + visitNode(cbNode, (node as PrivateIdentifierInInExpression).expression); case SyntaxKind.JsxElement: return visitNode(cbNode, (node as JsxElement).openingElement) || @@ -4446,9 +4449,32 @@ namespace ts { ); } + function parsePrivateIdentifierInInExpression(pos: number): Expression { + // PrivateIdentifierInInExpression[in]: + // [+in] PrivateIdentifier in RelationalExpression[?in] + + Debug.assert(token() === SyntaxKind.PrivateIdentifier, "parsePrivateIdentifierInInExpression should only have been called if we had a privateIdentifier"); + Debug.assert(inDisallowInContext() === false, "parsePrivateIdentifierInInExpression should only have been called if 'in' is allowed"); + const id = parsePrivateIdentifier(); + if (token() !== SyntaxKind.InKeyword) { + return createMissingNode(SyntaxKind.InKeyword, /*reportAtCurrentPosition*/ true, Diagnostics._0_expected, tokenToString(SyntaxKind.InKeyword)); + } + + const inToken = parseTokenNode>(); + const exp = parseBinaryExpressionOrHigher(OperatorPrecedence.Relational); + return finishNode(factory.createPrivateIdentifierInInExpression(id, inToken, exp), pos); + } + function parseBinaryExpressionOrHigher(precedence: OperatorPrecedence): Expression { + // parse a BinaryExpression the LHS is either: + // 1) a PrivateIdentifierInInExpression when 'in' flag allowed and lookahead matches 'PrivateIdentifier in' + // 2) a UnaryExpression + const pos = getNodePos(); - const leftOperand = parseUnaryExpressionOrHigher(); + const tryPrivateIdentifierInIn = token() === SyntaxKind.PrivateIdentifier && !inDisallowInContext() && lookAhead(nextTokenIsInKeyword); + const leftOperand = tryPrivateIdentifierInIn + ? parsePrivateIdentifierInInExpression(pos) + : parseUnaryExpressionOrHigher(); return parseBinaryExpressionRest(precedence, leftOperand, pos); } @@ -5977,6 +6003,11 @@ namespace ts { return (tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.NumericLiteral || token() === SyntaxKind.BigIntLiteral || token() === SyntaxKind.StringLiteral) && !scanner.hasPrecedingLineBreak(); } + function nextTokenIsInKeyword() { + nextToken(); + return token() === SyntaxKind.InKeyword; + } + function isDeclaration(): boolean { while (true) { switch (token()) { diff --git a/src/compiler/transformers/classFields.ts b/src/compiler/transformers/classFields.ts index e820851dde949..cda2b609dc5a2 100644 --- a/src/compiler/transformers/classFields.ts +++ b/src/compiler/transformers/classFields.ts @@ -176,6 +176,8 @@ namespace ts { return visitForStatement(node as ForStatement); case SyntaxKind.TaggedTemplateExpression: return visitTaggedTemplateExpression(node as TaggedTemplateExpression); + case SyntaxKind.PrivateIdentifierInInExpression: + return visitPrivateIdentifierInInExpression(node as PrivateIdentifierInInExpression); } return visitEachChild(node, visitor, context); } @@ -201,6 +203,27 @@ namespace ts { return setOriginalNode(factory.createIdentifier(""), node); } + /** + * Visits `#id in expr` + */ + function visitPrivateIdentifierInInExpression(node: PrivateIdentifierInInExpression) { + if (!shouldTransformPrivateElements) { + return node; + } + const info = accessPrivateIdentifier(node.name); + if (info) { + const receiver = visitNode(node.expression, visitor, isExpression); + + return setOriginalNode( + context.getEmitHelperFactory().createClassPrivateFieldInHelper(receiver, info.brandCheckIdentifier), + node + ); + } + + // Private name has not been declared. Subsequent transformers will handle this error + return visitEachChild(node, visitor, context); + } + /** * Visits the members of a class that has fields. * diff --git a/src/compiler/types.ts b/src/compiler/types.ts index a7ef444811925..d2120fc07d505 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -271,6 +271,7 @@ namespace ts { NonNullExpression, MetaProperty, SyntheticExpression, + PrivateIdentifierInInExpression, // Misc TemplateSpan, @@ -1035,6 +1036,7 @@ namespace ts { export type AssertsKeyword = KeywordToken; export type AwaitKeyword = KeywordToken; + export type InKeyword = KeywordToken; /** @deprecated Use `AwaitKeyword` instead. */ export type AwaitKeywordToken = AwaitKeyword; @@ -2328,6 +2330,13 @@ namespace ts { // see: https://tc39.github.io/ecma262/#prod-SuperProperty export type SuperProperty = SuperPropertyAccessExpression | SuperElementAccessExpression; + export interface PrivateIdentifierInInExpression extends Expression { + readonly kind: SyntaxKind.PrivateIdentifierInInExpression; + readonly name: PrivateIdentifier; + readonly inToken: Token; + readonly expression: Expression; + } + export interface CallExpression extends LeftHandSideExpression, Declaration { readonly kind: SyntaxKind.CallExpression; readonly expression: LeftHandSideExpression; @@ -7190,6 +7199,8 @@ namespace ts { updateNonNullChain(node: NonNullChain, expression: Expression): NonNullChain; createMetaProperty(keywordToken: MetaProperty["keywordToken"], name: Identifier): MetaProperty; updateMetaProperty(node: MetaProperty, name: Identifier): MetaProperty; + createPrivateIdentifierInInExpression(name: PrivateIdentifier, inToken: Token, expression: Expression): PrivateIdentifierInInExpression; + updatePrivateIdentifierInInExpression(node: PrivateIdentifierInInExpression, name: PrivateIdentifier, inToken: Token, expression: Expression): PrivateIdentifierInInExpression; // // Misc diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 83ee8d9da3606..13a5c1f636dd1 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1901,6 +1901,7 @@ namespace ts { case SyntaxKind.YieldExpression: case SyntaxKind.AwaitExpression: case SyntaxKind.MetaProperty: + case SyntaxKind.PrivateIdentifierInInExpression: return true; case SyntaxKind.QualifiedName: while (node.parent.kind === SyntaxKind.QualifiedName) { @@ -3625,6 +3626,7 @@ namespace ts { return OperatorPrecedence.Member; case SyntaxKind.AsExpression: + case SyntaxKind.PrivateIdentifierInInExpression: return OperatorPrecedence.Relational; case SyntaxKind.ThisKeyword: diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index b156908537953..fe04a682d398c 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -1562,6 +1562,7 @@ namespace ts { case SyntaxKind.OmittedExpression: case SyntaxKind.CommaListExpression: case SyntaxKind.PartiallyEmittedExpression: + case SyntaxKind.PrivateIdentifierInInExpression: return true; default: return isUnaryExpressionKind(kind); diff --git a/src/compiler/visitorPublic.ts b/src/compiler/visitorPublic.ts index 1758aa4397680..61bd204647187 100644 --- a/src/compiler/visitorPublic.ts +++ b/src/compiler/visitorPublic.ts @@ -793,6 +793,13 @@ namespace ts { nodeVisitor(node.operatorToken, tokenVisitor, isBinaryOperatorToken), nodeVisitor(node.right, visitor, isExpression)); + case SyntaxKind.PrivateIdentifierInInExpression: + Debug.type(node); + return factory.updatePrivateIdentifierInInExpression(node, + nodeVisitor((node).name, visitor, isMemberName), + nodeVisitor((node).inToken, tokenVisitor, isToken), + nodeVisitor((node).expression, visitor, isExpression)); + case SyntaxKind.ConditionalExpression: Debug.type(node); return factory.updateConditionalExpression(node, diff --git a/src/services/codefixes/fixSpelling.ts b/src/services/codefixes/fixSpelling.ts index 885f5d7c46188..705bf947eb416 100644 --- a/src/services/codefixes/fixSpelling.ts +++ b/src/services/codefixes/fixSpelling.ts @@ -54,6 +54,11 @@ namespace ts.codefix { } suggestedSymbol = checker.getSuggestedSymbolForNonexistentProperty(node, containingType); } + else if (isPrivateIdentifierInInExpression(parent) && parent.name === node) { + const receiverType = checker.getTypeAtLocation(parent.expression); + Debug.assert(isPrivateIdentifier(node), "Expected a privateIdentifier for spelling (in)"); + suggestedSymbol = checker.getSuggestedSymbolForNonexistentProperty(node, receiverType); + } else if (isQualifiedName(parent) && parent.right === node) { const symbol = checker.getSymbolAtLocation(parent.left); if (symbol && symbol.flags & SymbolFlags.Module) { diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 98f85301f5c3c..4ef574ab1f0bf 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -335,126 +335,127 @@ declare namespace ts { NonNullExpression = 227, MetaProperty = 228, SyntheticExpression = 229, - TemplateSpan = 230, - SemicolonClassElement = 231, - Block = 232, - EmptyStatement = 233, - VariableStatement = 234, - ExpressionStatement = 235, - IfStatement = 236, - DoStatement = 237, - WhileStatement = 238, - ForStatement = 239, - ForInStatement = 240, - ForOfStatement = 241, - ContinueStatement = 242, - BreakStatement = 243, - ReturnStatement = 244, - WithStatement = 245, - SwitchStatement = 246, - LabeledStatement = 247, - ThrowStatement = 248, - TryStatement = 249, - DebuggerStatement = 250, - VariableDeclaration = 251, - VariableDeclarationList = 252, - FunctionDeclaration = 253, - ClassDeclaration = 254, - InterfaceDeclaration = 255, - TypeAliasDeclaration = 256, - EnumDeclaration = 257, - ModuleDeclaration = 258, - ModuleBlock = 259, - CaseBlock = 260, - NamespaceExportDeclaration = 261, - ImportEqualsDeclaration = 262, - ImportDeclaration = 263, - ImportClause = 264, - NamespaceImport = 265, - NamedImports = 266, - ImportSpecifier = 267, - ExportAssignment = 268, - ExportDeclaration = 269, - NamedExports = 270, - NamespaceExport = 271, - ExportSpecifier = 272, - MissingDeclaration = 273, - ExternalModuleReference = 274, - JsxElement = 275, - JsxSelfClosingElement = 276, - JsxOpeningElement = 277, - JsxClosingElement = 278, - JsxFragment = 279, - JsxOpeningFragment = 280, - JsxClosingFragment = 281, - JsxAttribute = 282, - JsxAttributes = 283, - JsxSpreadAttribute = 284, - JsxExpression = 285, - CaseClause = 286, - DefaultClause = 287, - HeritageClause = 288, - CatchClause = 289, - PropertyAssignment = 290, - ShorthandPropertyAssignment = 291, - SpreadAssignment = 292, - EnumMember = 293, - UnparsedPrologue = 294, - UnparsedPrepend = 295, - UnparsedText = 296, - UnparsedInternalText = 297, - UnparsedSyntheticReference = 298, - SourceFile = 299, - Bundle = 300, - UnparsedSource = 301, - InputFiles = 302, - JSDocTypeExpression = 303, - JSDocNameReference = 304, - JSDocMemberName = 305, - JSDocAllType = 306, - JSDocUnknownType = 307, - JSDocNullableType = 308, - JSDocNonNullableType = 309, - JSDocOptionalType = 310, - JSDocFunctionType = 311, - JSDocVariadicType = 312, - JSDocNamepathType = 313, - JSDocComment = 314, - JSDocText = 315, - JSDocTypeLiteral = 316, - JSDocSignature = 317, - JSDocLink = 318, - JSDocLinkCode = 319, - JSDocLinkPlain = 320, - JSDocTag = 321, - JSDocAugmentsTag = 322, - JSDocImplementsTag = 323, - JSDocAuthorTag = 324, - JSDocDeprecatedTag = 325, - JSDocClassTag = 326, - JSDocPublicTag = 327, - JSDocPrivateTag = 328, - JSDocProtectedTag = 329, - JSDocReadonlyTag = 330, - JSDocOverrideTag = 331, - JSDocCallbackTag = 332, - JSDocEnumTag = 333, - JSDocParameterTag = 334, - JSDocReturnTag = 335, - JSDocThisTag = 336, - JSDocTypeTag = 337, - JSDocTemplateTag = 338, - JSDocTypedefTag = 339, - JSDocSeeTag = 340, - JSDocPropertyTag = 341, - SyntaxList = 342, - NotEmittedStatement = 343, - PartiallyEmittedExpression = 344, - CommaListExpression = 345, - MergeDeclarationMarker = 346, - EndOfDeclarationMarker = 347, - SyntheticReferenceExpression = 348, - Count = 349, + PrivateIdentifierInInExpression = 230, + TemplateSpan = 231, + SemicolonClassElement = 232, + Block = 233, + EmptyStatement = 234, + VariableStatement = 235, + ExpressionStatement = 236, + IfStatement = 237, + DoStatement = 238, + WhileStatement = 239, + ForStatement = 240, + ForInStatement = 241, + ForOfStatement = 242, + ContinueStatement = 243, + BreakStatement = 244, + ReturnStatement = 245, + WithStatement = 246, + SwitchStatement = 247, + LabeledStatement = 248, + ThrowStatement = 249, + TryStatement = 250, + DebuggerStatement = 251, + VariableDeclaration = 252, + VariableDeclarationList = 253, + FunctionDeclaration = 254, + ClassDeclaration = 255, + InterfaceDeclaration = 256, + TypeAliasDeclaration = 257, + EnumDeclaration = 258, + ModuleDeclaration = 259, + ModuleBlock = 260, + CaseBlock = 261, + NamespaceExportDeclaration = 262, + ImportEqualsDeclaration = 263, + ImportDeclaration = 264, + ImportClause = 265, + NamespaceImport = 266, + NamedImports = 267, + ImportSpecifier = 268, + ExportAssignment = 269, + ExportDeclaration = 270, + NamedExports = 271, + NamespaceExport = 272, + ExportSpecifier = 273, + MissingDeclaration = 274, + ExternalModuleReference = 275, + JsxElement = 276, + JsxSelfClosingElement = 277, + JsxOpeningElement = 278, + JsxClosingElement = 279, + JsxFragment = 280, + JsxOpeningFragment = 281, + JsxClosingFragment = 282, + JsxAttribute = 283, + JsxAttributes = 284, + JsxSpreadAttribute = 285, + JsxExpression = 286, + CaseClause = 287, + DefaultClause = 288, + HeritageClause = 289, + CatchClause = 290, + PropertyAssignment = 291, + ShorthandPropertyAssignment = 292, + SpreadAssignment = 293, + EnumMember = 294, + UnparsedPrologue = 295, + UnparsedPrepend = 296, + UnparsedText = 297, + UnparsedInternalText = 298, + UnparsedSyntheticReference = 299, + SourceFile = 300, + Bundle = 301, + UnparsedSource = 302, + InputFiles = 303, + JSDocTypeExpression = 304, + JSDocNameReference = 305, + JSDocMemberName = 306, + JSDocAllType = 307, + JSDocUnknownType = 308, + JSDocNullableType = 309, + JSDocNonNullableType = 310, + JSDocOptionalType = 311, + JSDocFunctionType = 312, + JSDocVariadicType = 313, + JSDocNamepathType = 314, + JSDocComment = 315, + JSDocText = 316, + JSDocTypeLiteral = 317, + JSDocSignature = 318, + JSDocLink = 319, + JSDocLinkCode = 320, + JSDocLinkPlain = 321, + JSDocTag = 322, + JSDocAugmentsTag = 323, + JSDocImplementsTag = 324, + JSDocAuthorTag = 325, + JSDocDeprecatedTag = 326, + JSDocClassTag = 327, + JSDocPublicTag = 328, + JSDocPrivateTag = 329, + JSDocProtectedTag = 330, + JSDocReadonlyTag = 331, + JSDocOverrideTag = 332, + JSDocCallbackTag = 333, + JSDocEnumTag = 334, + JSDocParameterTag = 335, + JSDocReturnTag = 336, + JSDocThisTag = 337, + JSDocTypeTag = 338, + JSDocTemplateTag = 339, + JSDocTypedefTag = 340, + JSDocSeeTag = 341, + JSDocPropertyTag = 342, + SyntaxList = 343, + NotEmittedStatement = 344, + PartiallyEmittedExpression = 345, + CommaListExpression = 346, + MergeDeclarationMarker = 347, + EndOfDeclarationMarker = 348, + SyntheticReferenceExpression = 349, + Count = 350, FirstAssignment = 63, LastAssignment = 78, FirstCompoundAssignment = 64, @@ -479,13 +480,13 @@ declare namespace ts { LastTemplateToken = 17, FirstBinaryOperator = 29, LastBinaryOperator = 78, - FirstStatement = 234, - LastStatement = 250, + FirstStatement = 235, + LastStatement = 251, FirstNode = 159, - FirstJSDocNode = 303, - LastJSDocNode = 341, - FirstJSDocTagNode = 321, - LastJSDocTagNode = 341, + FirstJSDocNode = 304, + LastJSDocNode = 342, + FirstJSDocTagNode = 322, + LastJSDocTagNode = 342, } export type TriviaSyntaxKind = SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia | SyntaxKind.NewLineTrivia | SyntaxKind.WhitespaceTrivia | SyntaxKind.ShebangTrivia | SyntaxKind.ConflictMarkerTrivia; export type LiteralSyntaxKind = SyntaxKind.NumericLiteral | SyntaxKind.BigIntLiteral | SyntaxKind.StringLiteral | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.RegularExpressionLiteral | SyntaxKind.NoSubstitutionTemplateLiteral; @@ -597,6 +598,7 @@ declare namespace ts { } export type AssertsKeyword = KeywordToken; export type AwaitKeyword = KeywordToken; + export type InKeyword = KeywordToken; /** @deprecated Use `AwaitKeyword` instead. */ export type AwaitKeywordToken = AwaitKeyword; /** @deprecated Use `AssertsKeyword` instead. */ @@ -1256,6 +1258,12 @@ declare namespace ts { readonly expression: SuperExpression; } export type SuperProperty = SuperPropertyAccessExpression | SuperElementAccessExpression; + export interface PrivateIdentifierInInExpression extends Expression { + readonly kind: SyntaxKind.PrivateIdentifierInInExpression; + readonly name: PrivateIdentifier; + readonly inToken: Token; + readonly expression: Expression; + } export interface CallExpression extends LeftHandSideExpression, Declaration { readonly kind: SyntaxKind.CallExpression; readonly expression: LeftHandSideExpression; @@ -3419,6 +3427,8 @@ declare namespace ts { updateNonNullChain(node: NonNullChain, expression: Expression): NonNullChain; createMetaProperty(keywordToken: MetaProperty["keywordToken"], name: Identifier): MetaProperty; updateMetaProperty(node: MetaProperty, name: Identifier): MetaProperty; + createPrivateIdentifierInInExpression(name: PrivateIdentifier, inToken: Token, expression: Expression): PrivateIdentifierInInExpression; + updatePrivateIdentifierInInExpression(node: PrivateIdentifierInInExpression, name: PrivateIdentifier, inToken: Token, expression: Expression): PrivateIdentifierInInExpression; createTemplateSpan(expression: Expression, literal: TemplateMiddle | TemplateTail): TemplateSpan; updateTemplateSpan(node: TemplateSpan, expression: Expression, literal: TemplateMiddle | TemplateTail): TemplateSpan; createSemicolonClassElement(): SemicolonClassElement; @@ -4517,6 +4527,7 @@ declare namespace ts { function isSyntheticExpression(node: Node): node is SyntheticExpression; function isPartiallyEmittedExpression(node: Node): node is PartiallyEmittedExpression; function isCommaListExpression(node: Node): node is CommaListExpression; + function isPrivateIdentifierInInExpression(node: Node): node is PrivateIdentifierInInExpression; function isTemplateSpan(node: Node): node is TemplateSpan; function isSemicolonClassElement(node: Node): node is SemicolonClassElement; function isBlock(node: Node): node is Block; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index cc33707287259..f43cc392ad545 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -335,126 +335,127 @@ declare namespace ts { NonNullExpression = 227, MetaProperty = 228, SyntheticExpression = 229, - TemplateSpan = 230, - SemicolonClassElement = 231, - Block = 232, - EmptyStatement = 233, - VariableStatement = 234, - ExpressionStatement = 235, - IfStatement = 236, - DoStatement = 237, - WhileStatement = 238, - ForStatement = 239, - ForInStatement = 240, - ForOfStatement = 241, - ContinueStatement = 242, - BreakStatement = 243, - ReturnStatement = 244, - WithStatement = 245, - SwitchStatement = 246, - LabeledStatement = 247, - ThrowStatement = 248, - TryStatement = 249, - DebuggerStatement = 250, - VariableDeclaration = 251, - VariableDeclarationList = 252, - FunctionDeclaration = 253, - ClassDeclaration = 254, - InterfaceDeclaration = 255, - TypeAliasDeclaration = 256, - EnumDeclaration = 257, - ModuleDeclaration = 258, - ModuleBlock = 259, - CaseBlock = 260, - NamespaceExportDeclaration = 261, - ImportEqualsDeclaration = 262, - ImportDeclaration = 263, - ImportClause = 264, - NamespaceImport = 265, - NamedImports = 266, - ImportSpecifier = 267, - ExportAssignment = 268, - ExportDeclaration = 269, - NamedExports = 270, - NamespaceExport = 271, - ExportSpecifier = 272, - MissingDeclaration = 273, - ExternalModuleReference = 274, - JsxElement = 275, - JsxSelfClosingElement = 276, - JsxOpeningElement = 277, - JsxClosingElement = 278, - JsxFragment = 279, - JsxOpeningFragment = 280, - JsxClosingFragment = 281, - JsxAttribute = 282, - JsxAttributes = 283, - JsxSpreadAttribute = 284, - JsxExpression = 285, - CaseClause = 286, - DefaultClause = 287, - HeritageClause = 288, - CatchClause = 289, - PropertyAssignment = 290, - ShorthandPropertyAssignment = 291, - SpreadAssignment = 292, - EnumMember = 293, - UnparsedPrologue = 294, - UnparsedPrepend = 295, - UnparsedText = 296, - UnparsedInternalText = 297, - UnparsedSyntheticReference = 298, - SourceFile = 299, - Bundle = 300, - UnparsedSource = 301, - InputFiles = 302, - JSDocTypeExpression = 303, - JSDocNameReference = 304, - JSDocMemberName = 305, - JSDocAllType = 306, - JSDocUnknownType = 307, - JSDocNullableType = 308, - JSDocNonNullableType = 309, - JSDocOptionalType = 310, - JSDocFunctionType = 311, - JSDocVariadicType = 312, - JSDocNamepathType = 313, - JSDocComment = 314, - JSDocText = 315, - JSDocTypeLiteral = 316, - JSDocSignature = 317, - JSDocLink = 318, - JSDocLinkCode = 319, - JSDocLinkPlain = 320, - JSDocTag = 321, - JSDocAugmentsTag = 322, - JSDocImplementsTag = 323, - JSDocAuthorTag = 324, - JSDocDeprecatedTag = 325, - JSDocClassTag = 326, - JSDocPublicTag = 327, - JSDocPrivateTag = 328, - JSDocProtectedTag = 329, - JSDocReadonlyTag = 330, - JSDocOverrideTag = 331, - JSDocCallbackTag = 332, - JSDocEnumTag = 333, - JSDocParameterTag = 334, - JSDocReturnTag = 335, - JSDocThisTag = 336, - JSDocTypeTag = 337, - JSDocTemplateTag = 338, - JSDocTypedefTag = 339, - JSDocSeeTag = 340, - JSDocPropertyTag = 341, - SyntaxList = 342, - NotEmittedStatement = 343, - PartiallyEmittedExpression = 344, - CommaListExpression = 345, - MergeDeclarationMarker = 346, - EndOfDeclarationMarker = 347, - SyntheticReferenceExpression = 348, - Count = 349, + PrivateIdentifierInInExpression = 230, + TemplateSpan = 231, + SemicolonClassElement = 232, + Block = 233, + EmptyStatement = 234, + VariableStatement = 235, + ExpressionStatement = 236, + IfStatement = 237, + DoStatement = 238, + WhileStatement = 239, + ForStatement = 240, + ForInStatement = 241, + ForOfStatement = 242, + ContinueStatement = 243, + BreakStatement = 244, + ReturnStatement = 245, + WithStatement = 246, + SwitchStatement = 247, + LabeledStatement = 248, + ThrowStatement = 249, + TryStatement = 250, + DebuggerStatement = 251, + VariableDeclaration = 252, + VariableDeclarationList = 253, + FunctionDeclaration = 254, + ClassDeclaration = 255, + InterfaceDeclaration = 256, + TypeAliasDeclaration = 257, + EnumDeclaration = 258, + ModuleDeclaration = 259, + ModuleBlock = 260, + CaseBlock = 261, + NamespaceExportDeclaration = 262, + ImportEqualsDeclaration = 263, + ImportDeclaration = 264, + ImportClause = 265, + NamespaceImport = 266, + NamedImports = 267, + ImportSpecifier = 268, + ExportAssignment = 269, + ExportDeclaration = 270, + NamedExports = 271, + NamespaceExport = 272, + ExportSpecifier = 273, + MissingDeclaration = 274, + ExternalModuleReference = 275, + JsxElement = 276, + JsxSelfClosingElement = 277, + JsxOpeningElement = 278, + JsxClosingElement = 279, + JsxFragment = 280, + JsxOpeningFragment = 281, + JsxClosingFragment = 282, + JsxAttribute = 283, + JsxAttributes = 284, + JsxSpreadAttribute = 285, + JsxExpression = 286, + CaseClause = 287, + DefaultClause = 288, + HeritageClause = 289, + CatchClause = 290, + PropertyAssignment = 291, + ShorthandPropertyAssignment = 292, + SpreadAssignment = 293, + EnumMember = 294, + UnparsedPrologue = 295, + UnparsedPrepend = 296, + UnparsedText = 297, + UnparsedInternalText = 298, + UnparsedSyntheticReference = 299, + SourceFile = 300, + Bundle = 301, + UnparsedSource = 302, + InputFiles = 303, + JSDocTypeExpression = 304, + JSDocNameReference = 305, + JSDocMemberName = 306, + JSDocAllType = 307, + JSDocUnknownType = 308, + JSDocNullableType = 309, + JSDocNonNullableType = 310, + JSDocOptionalType = 311, + JSDocFunctionType = 312, + JSDocVariadicType = 313, + JSDocNamepathType = 314, + JSDocComment = 315, + JSDocText = 316, + JSDocTypeLiteral = 317, + JSDocSignature = 318, + JSDocLink = 319, + JSDocLinkCode = 320, + JSDocLinkPlain = 321, + JSDocTag = 322, + JSDocAugmentsTag = 323, + JSDocImplementsTag = 324, + JSDocAuthorTag = 325, + JSDocDeprecatedTag = 326, + JSDocClassTag = 327, + JSDocPublicTag = 328, + JSDocPrivateTag = 329, + JSDocProtectedTag = 330, + JSDocReadonlyTag = 331, + JSDocOverrideTag = 332, + JSDocCallbackTag = 333, + JSDocEnumTag = 334, + JSDocParameterTag = 335, + JSDocReturnTag = 336, + JSDocThisTag = 337, + JSDocTypeTag = 338, + JSDocTemplateTag = 339, + JSDocTypedefTag = 340, + JSDocSeeTag = 341, + JSDocPropertyTag = 342, + SyntaxList = 343, + NotEmittedStatement = 344, + PartiallyEmittedExpression = 345, + CommaListExpression = 346, + MergeDeclarationMarker = 347, + EndOfDeclarationMarker = 348, + SyntheticReferenceExpression = 349, + Count = 350, FirstAssignment = 63, LastAssignment = 78, FirstCompoundAssignment = 64, @@ -479,13 +480,13 @@ declare namespace ts { LastTemplateToken = 17, FirstBinaryOperator = 29, LastBinaryOperator = 78, - FirstStatement = 234, - LastStatement = 250, + FirstStatement = 235, + LastStatement = 251, FirstNode = 159, - FirstJSDocNode = 303, - LastJSDocNode = 341, - FirstJSDocTagNode = 321, - LastJSDocTagNode = 341, + FirstJSDocNode = 304, + LastJSDocNode = 342, + FirstJSDocTagNode = 322, + LastJSDocTagNode = 342, } export type TriviaSyntaxKind = SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia | SyntaxKind.NewLineTrivia | SyntaxKind.WhitespaceTrivia | SyntaxKind.ShebangTrivia | SyntaxKind.ConflictMarkerTrivia; export type LiteralSyntaxKind = SyntaxKind.NumericLiteral | SyntaxKind.BigIntLiteral | SyntaxKind.StringLiteral | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.RegularExpressionLiteral | SyntaxKind.NoSubstitutionTemplateLiteral; @@ -597,6 +598,7 @@ declare namespace ts { } export type AssertsKeyword = KeywordToken; export type AwaitKeyword = KeywordToken; + export type InKeyword = KeywordToken; /** @deprecated Use `AwaitKeyword` instead. */ export type AwaitKeywordToken = AwaitKeyword; /** @deprecated Use `AssertsKeyword` instead. */ @@ -1256,6 +1258,12 @@ declare namespace ts { readonly expression: SuperExpression; } export type SuperProperty = SuperPropertyAccessExpression | SuperElementAccessExpression; + export interface PrivateIdentifierInInExpression extends Expression { + readonly kind: SyntaxKind.PrivateIdentifierInInExpression; + readonly name: PrivateIdentifier; + readonly inToken: Token; + readonly expression: Expression; + } export interface CallExpression extends LeftHandSideExpression, Declaration { readonly kind: SyntaxKind.CallExpression; readonly expression: LeftHandSideExpression; @@ -3419,6 +3427,8 @@ declare namespace ts { updateNonNullChain(node: NonNullChain, expression: Expression): NonNullChain; createMetaProperty(keywordToken: MetaProperty["keywordToken"], name: Identifier): MetaProperty; updateMetaProperty(node: MetaProperty, name: Identifier): MetaProperty; + createPrivateIdentifierInInExpression(name: PrivateIdentifier, inToken: Token, expression: Expression): PrivateIdentifierInInExpression; + updatePrivateIdentifierInInExpression(node: PrivateIdentifierInInExpression, name: PrivateIdentifier, inToken: Token, expression: Expression): PrivateIdentifierInInExpression; createTemplateSpan(expression: Expression, literal: TemplateMiddle | TemplateTail): TemplateSpan; updateTemplateSpan(node: TemplateSpan, expression: Expression, literal: TemplateMiddle | TemplateTail): TemplateSpan; createSemicolonClassElement(): SemicolonClassElement; @@ -4517,6 +4527,7 @@ declare namespace ts { function isSyntheticExpression(node: Node): node is SyntheticExpression; function isPartiallyEmittedExpression(node: Node): node is PartiallyEmittedExpression; function isCommaListExpression(node: Node): node is CommaListExpression; + function isPrivateIdentifierInInExpression(node: Node): node is PrivateIdentifierInInExpression; function isTemplateSpan(node: Node): node is TemplateSpan; function isSemicolonClassElement(node: Node): node is SemicolonClassElement; function isBlock(node: Node): node is Block; diff --git a/tests/baselines/reference/privateNameInInExpression.errors.txt b/tests/baselines/reference/privateNameInInExpression.errors.txt new file mode 100644 index 0000000000000..66152059feb4e --- /dev/null +++ b/tests/baselines/reference/privateNameInInExpression.errors.txt @@ -0,0 +1,140 @@ +tests/cases/conformance/classes/members/privateNames/privateNameInInExpression.ts(21,29): error TS2571: Object is of type 'unknown'. +tests/cases/conformance/classes/members/privateNames/privateNameInInExpression.ts(23,19): error TS2552: Cannot find name '#fiel'. Did you mean '#field'? +tests/cases/conformance/classes/members/privateNames/privateNameInInExpression.ts(25,20): error TS2304: Cannot find name '#field'. +tests/cases/conformance/classes/members/privateNames/privateNameInInExpression.ts(25,20): error TS18016: Private identifiers are not allowed outside class bodies. +tests/cases/conformance/classes/members/privateNames/privateNameInInExpression.ts(27,14): error TS2304: Cannot find name '#field'. +tests/cases/conformance/classes/members/privateNames/privateNameInInExpression.ts(27,14): error TS18016: Private identifiers are not allowed outside class bodies. +tests/cases/conformance/classes/members/privateNames/privateNameInInExpression.ts(29,23): error TS2407: The right-hand side of a 'for...in' statement must be of type 'any', an object type or a type parameter, but here has type 'boolean'. +tests/cases/conformance/classes/members/privateNames/privateNameInInExpression.ts(43,27): error TS2531: Object is possibly 'null'. +tests/cases/conformance/classes/members/privateNames/privateNameInInExpression.ts(108,12): error TS18016: Private identifiers are not allowed outside class bodies. + + +==== tests/cases/conformance/classes/members/privateNames/privateNameInInExpression.ts (9 errors) ==== + class Foo { + #field = 1; + static #staticField = 2; + #method() {} + static #staticMethod() {} + + goodRhs(v: any) { + const a = #field in v; + + const b = #field in v.p1.p2; + + const c = #field in (v as {}); + + const d = #field in (v as Foo); + + const e = #field in (v as never); + + for (let f in #field in v as any) { /**/ } // unlikely but valid + } + badRhs(v: any) { + const a = #field in (v as unknown); // Bad - RHS of in must be object type or any + ~~~~~~~~~~~~~~ +!!! error TS2571: Object is of type 'unknown'. + + const b = #fiel in v; // Bad - typo in privateID + ~~~~~ +!!! error TS2552: Cannot find name '#fiel'. Did you mean '#field'? + + const c = (#field) in v; // Bad - privateID is not an expression on its own + ~~~~~~ +!!! error TS2304: Cannot find name '#field'. + ~~~~~~ +!!! error TS18016: Private identifiers are not allowed outside class bodies. + + for (#field in v) { /**/ } // Bad - 'in' not allowed + ~~~~~~ +!!! error TS2304: Cannot find name '#field'. + ~~~~~~ +!!! error TS18016: Private identifiers are not allowed outside class bodies. + + for (let d in #field in v) { /**/ } // Bad - rhs of in should be a object/any + ~~~~~~~~~~~ +!!! error TS2407: The right-hand side of a 'for...in' statement must be of type 'any', an object type or a type parameter, but here has type 'boolean'. + } + whitespace(v: any) { + const a = v && /*0*/#field/*1*/ + /*2*/in/*3*/ + /*4*/v/*5*/ + } + flow(u: unknown, n: never, fb: Foo | Bar, fs: FooSub, b: Bar, fsb: FooSub | Bar) { + + if (typeof u === 'object') { + if (#field in n) { + n; // good n is never + } + + if (#field in u) { + ~ +!!! error TS2531: Object is possibly 'null'. + u; // good u is Foo + } else { + u; // good u is object | null + } + + if (u !== null) { + if (#field in u) { + u; // good u is Foo + } else { + u; // good u is object + } + + if (#method in u) { + u; // good u is Foo + } + + if (#staticField in u) { + u; // good u is typeof Foo + } + + if (#staticMethod in u) { + u; // good u is typeof Foo + } + } + } + + if (#field in fb) { + fb; // good fb is Foo + } else { + fb; // good fb is Bar + } + + if (#field in fs) { + fs; // good fs is FooSub + } else { + fs; // good fs is never + } + + if (#field in b) { + b; // good b is 'Bar & Foo' + } else { + b; // good b is Bar + } + + if (#field in fsb) { + fsb; // good fsb is FooSub + } else { + fsb; // good fsb is Bar + } + + class Nested { + m(v: any) { + if (#field in v) { + v; // good v is Foo + } + } + } + } + } + + class FooSub extends Foo { subTypeOfFoo = true } + class Bar { notFoo = true } + + function badSyntax(v: Foo) { + return #field in v; // Bad - outside of class + ~~~~~~ +!!! error TS18016: Private identifiers are not allowed outside class bodies. + } + \ No newline at end of file diff --git a/tests/baselines/reference/privateNameInInExpression.js b/tests/baselines/reference/privateNameInInExpression.js new file mode 100644 index 0000000000000..000620cb6d561 --- /dev/null +++ b/tests/baselines/reference/privateNameInInExpression.js @@ -0,0 +1,210 @@ +//// [privateNameInInExpression.ts] +class Foo { + #field = 1; + static #staticField = 2; + #method() {} + static #staticMethod() {} + + goodRhs(v: any) { + const a = #field in v; + + const b = #field in v.p1.p2; + + const c = #field in (v as {}); + + const d = #field in (v as Foo); + + const e = #field in (v as never); + + for (let f in #field in v as any) { /**/ } // unlikely but valid + } + badRhs(v: any) { + const a = #field in (v as unknown); // Bad - RHS of in must be object type or any + + const b = #fiel in v; // Bad - typo in privateID + + const c = (#field) in v; // Bad - privateID is not an expression on its own + + for (#field in v) { /**/ } // Bad - 'in' not allowed + + for (let d in #field in v) { /**/ } // Bad - rhs of in should be a object/any + } + whitespace(v: any) { + const a = v && /*0*/#field/*1*/ + /*2*/in/*3*/ + /*4*/v/*5*/ + } + flow(u: unknown, n: never, fb: Foo | Bar, fs: FooSub, b: Bar, fsb: FooSub | Bar) { + + if (typeof u === 'object') { + if (#field in n) { + n; // good n is never + } + + if (#field in u) { + u; // good u is Foo + } else { + u; // good u is object | null + } + + if (u !== null) { + if (#field in u) { + u; // good u is Foo + } else { + u; // good u is object + } + + if (#method in u) { + u; // good u is Foo + } + + if (#staticField in u) { + u; // good u is typeof Foo + } + + if (#staticMethod in u) { + u; // good u is typeof Foo + } + } + } + + if (#field in fb) { + fb; // good fb is Foo + } else { + fb; // good fb is Bar + } + + if (#field in fs) { + fs; // good fs is FooSub + } else { + fs; // good fs is never + } + + if (#field in b) { + b; // good b is 'Bar & Foo' + } else { + b; // good b is Bar + } + + if (#field in fsb) { + fsb; // good fsb is FooSub + } else { + fsb; // good fsb is Bar + } + + class Nested { + m(v: any) { + if (#field in v) { + v; // good v is Foo + } + } + } + } +} + +class FooSub extends Foo { subTypeOfFoo = true } +class Bar { notFoo = true } + +function badSyntax(v: Foo) { + return #field in v; // Bad - outside of class +} + + +//// [privateNameInInExpression.js] +"use strict"; +class Foo { + #field = 1; + static #staticField = 2; + #method() { } + static #staticMethod() { } + goodRhs(v) { + const a = #field in v; + const b = #field in v.p1.p2; + const c = #field in v; + const d = #field in v; + const e = #field in v; + for (let f in #field in v) { /**/ } // unlikely but valid + } + badRhs(v) { + const a = #field in v; // Bad - RHS of in must be object type or any + const b = #fiel in v; // Bad - typo in privateID + const c = (#field) in v; // Bad - privateID is not an expression on its own + for (#field in v) { /**/ } // Bad - 'in' not allowed + for (let d in #field in v) { /**/ } // Bad - rhs of in should be a object/any + } + whitespace(v) { + const a = v && /*0*/ #field/*1*/ + /*2*/ in /*3*/ + /*4*/ v; /*5*/ + } + flow(u, n, fb, fs, b, fsb) { + if (typeof u === 'object') { + if (#field in n) { + n; // good n is never + } + if (#field in u) { + u; // good u is Foo + } + else { + u; // good u is object | null + } + if (u !== null) { + if (#field in u) { + u; // good u is Foo + } + else { + u; // good u is object + } + if (#method in u) { + u; // good u is Foo + } + if (#staticField in u) { + u; // good u is typeof Foo + } + if (#staticMethod in u) { + u; // good u is typeof Foo + } + } + } + if (#field in fb) { + fb; // good fb is Foo + } + else { + fb; // good fb is Bar + } + if (#field in fs) { + fs; // good fs is FooSub + } + else { + fs; // good fs is never + } + if (#field in b) { + b; // good b is 'Bar & Foo' + } + else { + b; // good b is Bar + } + if (#field in fsb) { + fsb; // good fsb is FooSub + } + else { + fsb; // good fsb is Bar + } + class Nested { + m(v) { + if (#field in v) { + v; // good v is Foo + } + } + } + } +} +class FooSub extends Foo { + subTypeOfFoo = true; +} +class Bar { + notFoo = true; +} +function badSyntax(v) { + return #field in v; // Bad - outside of class +} diff --git a/tests/baselines/reference/privateNameInInExpression.symbols b/tests/baselines/reference/privateNameInInExpression.symbols new file mode 100644 index 0000000000000..30a02dddacea9 --- /dev/null +++ b/tests/baselines/reference/privateNameInInExpression.symbols @@ -0,0 +1,233 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameInInExpression.ts === +class Foo { +>Foo : Symbol(Foo, Decl(privateNameInInExpression.ts, 0, 0)) + + #field = 1; +>#field : Symbol(Foo.#field, Decl(privateNameInInExpression.ts, 0, 11)) + + static #staticField = 2; +>#staticField : Symbol(Foo.#staticField, Decl(privateNameInInExpression.ts, 1, 15)) + + #method() {} +>#method : Symbol(Foo.#method, Decl(privateNameInInExpression.ts, 2, 28)) + + static #staticMethod() {} +>#staticMethod : Symbol(Foo.#staticMethod, Decl(privateNameInInExpression.ts, 3, 16)) + + goodRhs(v: any) { +>goodRhs : Symbol(Foo.goodRhs, Decl(privateNameInInExpression.ts, 4, 29)) +>v : Symbol(v, Decl(privateNameInInExpression.ts, 6, 12)) + + const a = #field in v; +>a : Symbol(a, Decl(privateNameInInExpression.ts, 7, 13)) +>v : Symbol(v, Decl(privateNameInInExpression.ts, 6, 12)) + + const b = #field in v.p1.p2; +>b : Symbol(b, Decl(privateNameInInExpression.ts, 9, 13)) +>v : Symbol(v, Decl(privateNameInInExpression.ts, 6, 12)) + + const c = #field in (v as {}); +>c : Symbol(c, Decl(privateNameInInExpression.ts, 11, 13)) +>v : Symbol(v, Decl(privateNameInInExpression.ts, 6, 12)) + + const d = #field in (v as Foo); +>d : Symbol(d, Decl(privateNameInInExpression.ts, 13, 13)) +>v : Symbol(v, Decl(privateNameInInExpression.ts, 6, 12)) +>Foo : Symbol(Foo, Decl(privateNameInInExpression.ts, 0, 0)) + + const e = #field in (v as never); +>e : Symbol(e, Decl(privateNameInInExpression.ts, 15, 13)) +>v : Symbol(v, Decl(privateNameInInExpression.ts, 6, 12)) + + for (let f in #field in v as any) { /**/ } // unlikely but valid +>f : Symbol(f, Decl(privateNameInInExpression.ts, 17, 16)) +>v : Symbol(v, Decl(privateNameInInExpression.ts, 6, 12)) + } + badRhs(v: any) { +>badRhs : Symbol(Foo.badRhs, Decl(privateNameInInExpression.ts, 18, 5)) +>v : Symbol(v, Decl(privateNameInInExpression.ts, 19, 11)) + + const a = #field in (v as unknown); // Bad - RHS of in must be object type or any +>a : Symbol(a, Decl(privateNameInInExpression.ts, 20, 13)) +>v : Symbol(v, Decl(privateNameInInExpression.ts, 19, 11)) + + const b = #fiel in v; // Bad - typo in privateID +>b : Symbol(b, Decl(privateNameInInExpression.ts, 22, 13)) +>v : Symbol(v, Decl(privateNameInInExpression.ts, 19, 11)) + + const c = (#field) in v; // Bad - privateID is not an expression on its own +>c : Symbol(c, Decl(privateNameInInExpression.ts, 24, 13)) +>v : Symbol(v, Decl(privateNameInInExpression.ts, 19, 11)) + + for (#field in v) { /**/ } // Bad - 'in' not allowed +>v : Symbol(v, Decl(privateNameInInExpression.ts, 19, 11)) + + for (let d in #field in v) { /**/ } // Bad - rhs of in should be a object/any +>d : Symbol(d, Decl(privateNameInInExpression.ts, 28, 16)) +>v : Symbol(v, Decl(privateNameInInExpression.ts, 19, 11)) + } + whitespace(v: any) { +>whitespace : Symbol(Foo.whitespace, Decl(privateNameInInExpression.ts, 29, 5)) +>v : Symbol(v, Decl(privateNameInInExpression.ts, 30, 15)) + + const a = v && /*0*/#field/*1*/ +>a : Symbol(a, Decl(privateNameInInExpression.ts, 31, 13)) +>v : Symbol(v, Decl(privateNameInInExpression.ts, 30, 15)) + + /*2*/in/*3*/ + /*4*/v/*5*/ +>v : Symbol(v, Decl(privateNameInInExpression.ts, 30, 15)) + } + flow(u: unknown, n: never, fb: Foo | Bar, fs: FooSub, b: Bar, fsb: FooSub | Bar) { +>flow : Symbol(Foo.flow, Decl(privateNameInInExpression.ts, 34, 5)) +>u : Symbol(u, Decl(privateNameInInExpression.ts, 35, 9)) +>n : Symbol(n, Decl(privateNameInInExpression.ts, 35, 20)) +>fb : Symbol(fb, Decl(privateNameInInExpression.ts, 35, 30)) +>Foo : Symbol(Foo, Decl(privateNameInInExpression.ts, 0, 0)) +>Bar : Symbol(Bar, Decl(privateNameInInExpression.ts, 103, 48)) +>fs : Symbol(fs, Decl(privateNameInInExpression.ts, 35, 45)) +>FooSub : Symbol(FooSub, Decl(privateNameInInExpression.ts, 101, 1)) +>b : Symbol(b, Decl(privateNameInInExpression.ts, 35, 57)) +>Bar : Symbol(Bar, Decl(privateNameInInExpression.ts, 103, 48)) +>fsb : Symbol(fsb, Decl(privateNameInInExpression.ts, 35, 65)) +>FooSub : Symbol(FooSub, Decl(privateNameInInExpression.ts, 101, 1)) +>Bar : Symbol(Bar, Decl(privateNameInInExpression.ts, 103, 48)) + + if (typeof u === 'object') { +>u : Symbol(u, Decl(privateNameInInExpression.ts, 35, 9)) + + if (#field in n) { +>n : Symbol(n, Decl(privateNameInInExpression.ts, 35, 20)) + + n; // good n is never +>n : Symbol(n, Decl(privateNameInInExpression.ts, 35, 20)) + } + + if (#field in u) { +>u : Symbol(u, Decl(privateNameInInExpression.ts, 35, 9)) + + u; // good u is Foo +>u : Symbol(u, Decl(privateNameInInExpression.ts, 35, 9)) + + } else { + u; // good u is object | null +>u : Symbol(u, Decl(privateNameInInExpression.ts, 35, 9)) + } + + if (u !== null) { +>u : Symbol(u, Decl(privateNameInInExpression.ts, 35, 9)) + + if (#field in u) { +>u : Symbol(u, Decl(privateNameInInExpression.ts, 35, 9)) + + u; // good u is Foo +>u : Symbol(u, Decl(privateNameInInExpression.ts, 35, 9)) + + } else { + u; // good u is object +>u : Symbol(u, Decl(privateNameInInExpression.ts, 35, 9)) + } + + if (#method in u) { +>u : Symbol(u, Decl(privateNameInInExpression.ts, 35, 9)) + + u; // good u is Foo +>u : Symbol(u, Decl(privateNameInInExpression.ts, 35, 9)) + } + + if (#staticField in u) { +>u : Symbol(u, Decl(privateNameInInExpression.ts, 35, 9)) + + u; // good u is typeof Foo +>u : Symbol(u, Decl(privateNameInInExpression.ts, 35, 9)) + } + + if (#staticMethod in u) { +>u : Symbol(u, Decl(privateNameInInExpression.ts, 35, 9)) + + u; // good u is typeof Foo +>u : Symbol(u, Decl(privateNameInInExpression.ts, 35, 9)) + } + } + } + + if (#field in fb) { +>fb : Symbol(fb, Decl(privateNameInInExpression.ts, 35, 30)) + + fb; // good fb is Foo +>fb : Symbol(fb, Decl(privateNameInInExpression.ts, 35, 30)) + + } else { + fb; // good fb is Bar +>fb : Symbol(fb, Decl(privateNameInInExpression.ts, 35, 30)) + } + + if (#field in fs) { +>fs : Symbol(fs, Decl(privateNameInInExpression.ts, 35, 45)) + + fs; // good fs is FooSub +>fs : Symbol(fs, Decl(privateNameInInExpression.ts, 35, 45)) + + } else { + fs; // good fs is never +>fs : Symbol(fs, Decl(privateNameInInExpression.ts, 35, 45)) + } + + if (#field in b) { +>b : Symbol(b, Decl(privateNameInInExpression.ts, 35, 57)) + + b; // good b is 'Bar & Foo' +>b : Symbol(b, Decl(privateNameInInExpression.ts, 35, 57)) + + } else { + b; // good b is Bar +>b : Symbol(b, Decl(privateNameInInExpression.ts, 35, 57)) + } + + if (#field in fsb) { +>fsb : Symbol(fsb, Decl(privateNameInInExpression.ts, 35, 65)) + + fsb; // good fsb is FooSub +>fsb : Symbol(fsb, Decl(privateNameInInExpression.ts, 35, 65)) + + } else { + fsb; // good fsb is Bar +>fsb : Symbol(fsb, Decl(privateNameInInExpression.ts, 35, 65)) + } + + class Nested { +>Nested : Symbol(Nested, Decl(privateNameInInExpression.ts, 91, 9)) + + m(v: any) { +>m : Symbol(Nested.m, Decl(privateNameInInExpression.ts, 93, 22)) +>v : Symbol(v, Decl(privateNameInInExpression.ts, 94, 14)) + + if (#field in v) { +>v : Symbol(v, Decl(privateNameInInExpression.ts, 94, 14)) + + v; // good v is Foo +>v : Symbol(v, Decl(privateNameInInExpression.ts, 94, 14)) + } + } + } + } +} + +class FooSub extends Foo { subTypeOfFoo = true } +>FooSub : Symbol(FooSub, Decl(privateNameInInExpression.ts, 101, 1)) +>Foo : Symbol(Foo, Decl(privateNameInInExpression.ts, 0, 0)) +>subTypeOfFoo : Symbol(FooSub.subTypeOfFoo, Decl(privateNameInInExpression.ts, 103, 26)) + +class Bar { notFoo = true } +>Bar : Symbol(Bar, Decl(privateNameInInExpression.ts, 103, 48)) +>notFoo : Symbol(Bar.notFoo, Decl(privateNameInInExpression.ts, 104, 11)) + +function badSyntax(v: Foo) { +>badSyntax : Symbol(badSyntax, Decl(privateNameInInExpression.ts, 104, 27)) +>v : Symbol(v, Decl(privateNameInInExpression.ts, 106, 19)) +>Foo : Symbol(Foo, Decl(privateNameInInExpression.ts, 0, 0)) + + return #field in v; // Bad - outside of class +>v : Symbol(v, Decl(privateNameInInExpression.ts, 106, 19)) +} + diff --git a/tests/baselines/reference/privateNameInInExpression.types b/tests/baselines/reference/privateNameInInExpression.types new file mode 100644 index 0000000000000..f323b2a6a2dc3 --- /dev/null +++ b/tests/baselines/reference/privateNameInInExpression.types @@ -0,0 +1,274 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameInInExpression.ts === +class Foo { +>Foo : Foo + + #field = 1; +>#field : number +>1 : 1 + + static #staticField = 2; +>#staticField : number +>2 : 2 + + #method() {} +>#method : () => void + + static #staticMethod() {} +>#staticMethod : () => void + + goodRhs(v: any) { +>goodRhs : (v: any) => void +>v : any + + const a = #field in v; +>a : boolean +>#field in v : boolean +>v : any + + const b = #field in v.p1.p2; +>b : boolean +>#field in v.p1.p2 : boolean +>v.p1.p2 : any +>v.p1 : any +>v : any +>p1 : any +>p2 : any + + const c = #field in (v as {}); +>c : boolean +>#field in (v as {}) : boolean +>(v as {}) : {} +>v as {} : {} +>v : any + + const d = #field in (v as Foo); +>d : boolean +>#field in (v as Foo) : boolean +>(v as Foo) : Foo +>v as Foo : Foo +>v : any + + const e = #field in (v as never); +>e : boolean +>#field in (v as never) : boolean +>(v as never) : never +>v as never : never +>v : any + + for (let f in #field in v as any) { /**/ } // unlikely but valid +>f : string +>#field in v as any : any +>#field in v : boolean +>v : any + } + badRhs(v: any) { +>badRhs : (v: any) => void +>v : any + + const a = #field in (v as unknown); // Bad - RHS of in must be object type or any +>a : boolean +>#field in (v as unknown) : boolean +>(v as unknown) : unknown +>v as unknown : unknown +>v : any + + const b = #fiel in v; // Bad - typo in privateID +>b : any +>#fiel in v : any +>v : any + + const c = (#field) in v; // Bad - privateID is not an expression on its own +>c : boolean +>(#field) in v : boolean +>(#field) : any +>#field : any +>v : any + + for (#field in v) { /**/ } // Bad - 'in' not allowed +>#field : any +>v : any + + for (let d in #field in v) { /**/ } // Bad - rhs of in should be a object/any +>d : string +>#field in v : boolean +>v : any + } + whitespace(v: any) { +>whitespace : (v: any) => void +>v : any + + const a = v && /*0*/#field/*1*/ +>a : any +>v && /*0*/#field/*1*/ /*2*/in/*3*/ /*4*/v : any +>v : any +>#field/*1*/ /*2*/in/*3*/ /*4*/v : boolean + + /*2*/in/*3*/ + /*4*/v/*5*/ +>v : any + } + flow(u: unknown, n: never, fb: Foo | Bar, fs: FooSub, b: Bar, fsb: FooSub | Bar) { +>flow : (u: unknown, n: never, fb: Foo | Bar, fs: FooSub, b: Bar, fsb: FooSub | Bar) => void +>u : unknown +>n : never +>fb : Foo | Bar +>fs : FooSub +>b : Bar +>fsb : Bar | FooSub + + if (typeof u === 'object') { +>typeof u === 'object' : boolean +>typeof u : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>u : unknown +>'object' : "object" + + if (#field in n) { +>#field in n : boolean +>n : never + + n; // good n is never +>n : never + } + + if (#field in u) { +>#field in u : boolean +>u : object | null + + u; // good u is Foo +>u : Foo + + } else { + u; // good u is object | null +>u : object | null + } + + if (u !== null) { +>u !== null : boolean +>u : object | null +>null : null + + if (#field in u) { +>#field in u : boolean +>u : object + + u; // good u is Foo +>u : Foo + + } else { + u; // good u is object +>u : object + } + + if (#method in u) { +>#method in u : boolean +>u : object + + u; // good u is Foo +>u : Foo + } + + if (#staticField in u) { +>#staticField in u : boolean +>u : object + + u; // good u is typeof Foo +>u : typeof Foo + } + + if (#staticMethod in u) { +>#staticMethod in u : boolean +>u : object + + u; // good u is typeof Foo +>u : typeof Foo + } + } + } + + if (#field in fb) { +>#field in fb : boolean +>fb : Foo | Bar + + fb; // good fb is Foo +>fb : Foo + + } else { + fb; // good fb is Bar +>fb : Bar + } + + if (#field in fs) { +>#field in fs : boolean +>fs : FooSub + + fs; // good fs is FooSub +>fs : FooSub + + } else { + fs; // good fs is never +>fs : never + } + + if (#field in b) { +>#field in b : boolean +>b : Bar + + b; // good b is 'Bar & Foo' +>b : Bar & Foo + + } else { + b; // good b is Bar +>b : Bar + } + + if (#field in fsb) { +>#field in fsb : boolean +>fsb : Bar | FooSub + + fsb; // good fsb is FooSub +>fsb : FooSub + + } else { + fsb; // good fsb is Bar +>fsb : Bar + } + + class Nested { +>Nested : Nested + + m(v: any) { +>m : (v: any) => void +>v : any + + if (#field in v) { +>#field in v : boolean +>v : any + + v; // good v is Foo +>v : Foo + } + } + } + } +} + +class FooSub extends Foo { subTypeOfFoo = true } +>FooSub : FooSub +>Foo : Foo +>subTypeOfFoo : boolean +>true : true + +class Bar { notFoo = true } +>Bar : Bar +>notFoo : boolean +>true : true + +function badSyntax(v: Foo) { +>badSyntax : (v: Foo) => any +>v : Foo + + return #field in v; // Bad - outside of class +>#field in v : any +>v : Foo +} + diff --git a/tests/baselines/reference/privateNameInInExpressionTransform.errors.txt b/tests/baselines/reference/privateNameInInExpressionTransform.errors.txt new file mode 100644 index 0000000000000..0368b9ef750bc --- /dev/null +++ b/tests/baselines/reference/privateNameInInExpressionTransform.errors.txt @@ -0,0 +1,67 @@ +tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts(20,14): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts(20,24): error TS2361: The right-hand side of an 'in' expression must not be a primitive. +tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts(22,14): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts(29,21): error TS1005: ';' expected. +tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts(30,21): error TS1005: ';' expected. +tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts(42,12): error TS18016: Private identifiers are not allowed outside class bodies. + + +==== tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts (6 errors) ==== + class Foo { + #field = 1; + #method() {} + static #staticField= 2; + static #staticMethod() {} + + check(v: any) { + #field in v; // expect Foo's 'field' WeakMap + #method in v; // expect Foo's 'method' WeakSet + #staticField in v; // expect Foo's constructor + #staticMethod in v; // expect Foo's constructor + } + precedence(v: any) { + // '==' has lower precedence than 'in' + // '<' has same precedence than 'in' + // '<<' has higher precedence than 'in' + + v == #field in v == v; // Good precedence: ((v == (#field in v)) == v) + + v << #field in v << v; // Good precedence: (v << (#field in (v << v))) + ~~~~~~~~~~~~~~~~ +!!! error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. + ~~~~~~ +!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive. + + v << #field in v == v; // Good precedence: ((v << (#field in v)) == v) + ~~~~~~~~~~~ +!!! error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. + + v == #field in v < v; // Good precedence: (v == ((#field in v) < v)) + + #field in v && #field in v; // Good precedence: ((#field in v) && (#field in v)) + } + invalidLHS(v: any) { + 'prop' in v = 10; + ~ +!!! error TS1005: ';' expected. + #field in v = 10; + ~ +!!! error TS1005: ';' expected. + } + } + + class Bar { + #field = 1; + check(v: any) { + #field in v; // expect Bar's 'field' WeakMap + } + } + + function syntaxError(v: Foo) { + return #field in v; // expect `return in v` so runtime will have a syntax error + ~~~~~~ +!!! error TS18016: Private identifiers are not allowed outside class bodies. + } + + export { } + \ No newline at end of file diff --git a/tests/baselines/reference/privateNameInInExpressionTransform.js b/tests/baselines/reference/privateNameInInExpressionTransform.js new file mode 100644 index 0000000000000..cd7d3dbc61db2 --- /dev/null +++ b/tests/baselines/reference/privateNameInInExpressionTransform.js @@ -0,0 +1,97 @@ +//// [privateNameInInExpressionTransform.ts] +class Foo { + #field = 1; + #method() {} + static #staticField= 2; + static #staticMethod() {} + + check(v: any) { + #field in v; // expect Foo's 'field' WeakMap + #method in v; // expect Foo's 'method' WeakSet + #staticField in v; // expect Foo's constructor + #staticMethod in v; // expect Foo's constructor + } + precedence(v: any) { + // '==' has lower precedence than 'in' + // '<' has same precedence than 'in' + // '<<' has higher precedence than 'in' + + v == #field in v == v; // Good precedence: ((v == (#field in v)) == v) + + v << #field in v << v; // Good precedence: (v << (#field in (v << v))) + + v << #field in v == v; // Good precedence: ((v << (#field in v)) == v) + + v == #field in v < v; // Good precedence: (v == ((#field in v) < v)) + + #field in v && #field in v; // Good precedence: ((#field in v) && (#field in v)) + } + invalidLHS(v: any) { + 'prop' in v = 10; + #field in v = 10; + } +} + +class Bar { + #field = 1; + check(v: any) { + #field in v; // expect Bar's 'field' WeakMap + } +} + +function syntaxError(v: Foo) { + return #field in v; // expect `return in v` so runtime will have a syntax error +} + +export { } + + +//// [privateNameInInExpressionTransform.js] +var __classPrivateFieldIn = (this && this.__classPrivateFieldIn) || function(receiver, state) { + if (receiver === null || (typeof receiver !== "object" && typeof receiver !== "function")) throw new TypeError("Cannot use 'in' operator on non-object"); + return typeof state === "function" ? receiver === state : state.has(receiver); +}; +var _Foo_instances, _a, _Foo_field, _Foo_method, _Foo_staticField, _Foo_staticMethod, _Bar_field; +class Foo { + constructor() { + _Foo_instances.add(this); + _Foo_field.set(this, 1); + } + check(v) { + __classPrivateFieldIn(v, _Foo_field); // expect Foo's 'field' WeakMap + __classPrivateFieldIn(v, _Foo_instances); // expect Foo's 'method' WeakSet + __classPrivateFieldIn(v, _a); // expect Foo's constructor + __classPrivateFieldIn(v, _a); // expect Foo's constructor + } + precedence(v) { + // '==' has lower precedence than 'in' + // '<' has same precedence than 'in' + // '<<' has higher precedence than 'in' + v == __classPrivateFieldIn(v, _Foo_field) == v; // Good precedence: ((v == (#field in v)) == v) + v << __classPrivateFieldIn(v << v, _Foo_field); // Good precedence: (v << (#field in (v << v))) + v << __classPrivateFieldIn(v, _Foo_field) == v; // Good precedence: ((v << (#field in v)) == v) + v == __classPrivateFieldIn(v, _Foo_field) < v; // Good precedence: (v == ((#field in v) < v)) + __classPrivateFieldIn(v, _Foo_field) && __classPrivateFieldIn(v, _Foo_field); // Good precedence: ((#field in v) && (#field in v)) + } + invalidLHS(v) { + 'prop' in v; + 10; + __classPrivateFieldIn(v, _Foo_field); + 10; + } +} +_a = Foo, _Foo_field = new WeakMap(), _Foo_instances = new WeakSet(), _Foo_method = function _Foo_method() { }, _Foo_staticMethod = function _Foo_staticMethod() { }; +_Foo_staticField = { value: 2 }; +class Bar { + constructor() { + _Bar_field.set(this, 1); + } + check(v) { + __classPrivateFieldIn(v, _Bar_field); // expect Bar's 'field' WeakMap + } +} +_Bar_field = new WeakMap(); +function syntaxError(v) { + return in v; // expect `return in v` so runtime will have a syntax error +} +export {}; diff --git a/tests/baselines/reference/privateNameInInExpressionTransform.symbols b/tests/baselines/reference/privateNameInInExpressionTransform.symbols new file mode 100644 index 0000000000000..c0cc9938cd8d2 --- /dev/null +++ b/tests/baselines/reference/privateNameInInExpressionTransform.symbols @@ -0,0 +1,102 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts === +class Foo { +>Foo : Symbol(Foo, Decl(privateNameInInExpressionTransform.ts, 0, 0)) + + #field = 1; +>#field : Symbol(Foo.#field, Decl(privateNameInInExpressionTransform.ts, 0, 11)) + + #method() {} +>#method : Symbol(Foo.#method, Decl(privateNameInInExpressionTransform.ts, 1, 15)) + + static #staticField= 2; +>#staticField : Symbol(Foo.#staticField, Decl(privateNameInInExpressionTransform.ts, 2, 16)) + + static #staticMethod() {} +>#staticMethod : Symbol(Foo.#staticMethod, Decl(privateNameInInExpressionTransform.ts, 3, 27)) + + check(v: any) { +>check : Symbol(Foo.check, Decl(privateNameInInExpressionTransform.ts, 4, 29)) +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 6, 10)) + + #field in v; // expect Foo's 'field' WeakMap +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 6, 10)) + + #method in v; // expect Foo's 'method' WeakSet +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 6, 10)) + + #staticField in v; // expect Foo's constructor +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 6, 10)) + + #staticMethod in v; // expect Foo's constructor +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 6, 10)) + } + precedence(v: any) { +>precedence : Symbol(Foo.precedence, Decl(privateNameInInExpressionTransform.ts, 11, 5)) +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 12, 15)) + + // '==' has lower precedence than 'in' + // '<' has same precedence than 'in' + // '<<' has higher precedence than 'in' + + v == #field in v == v; // Good precedence: ((v == (#field in v)) == v) +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 12, 15)) +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 12, 15)) +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 12, 15)) + + v << #field in v << v; // Good precedence: (v << (#field in (v << v))) +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 12, 15)) +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 12, 15)) +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 12, 15)) + + v << #field in v == v; // Good precedence: ((v << (#field in v)) == v) +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 12, 15)) +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 12, 15)) +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 12, 15)) + + v == #field in v < v; // Good precedence: (v == ((#field in v) < v)) +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 12, 15)) +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 12, 15)) +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 12, 15)) + + #field in v && #field in v; // Good precedence: ((#field in v) && (#field in v)) +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 12, 15)) +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 12, 15)) + } + invalidLHS(v: any) { +>invalidLHS : Symbol(Foo.invalidLHS, Decl(privateNameInInExpressionTransform.ts, 26, 5)) +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 27, 15)) + + 'prop' in v = 10; +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 27, 15)) + + #field in v = 10; +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 27, 15)) + } +} + +class Bar { +>Bar : Symbol(Bar, Decl(privateNameInInExpressionTransform.ts, 31, 1)) + + #field = 1; +>#field : Symbol(Bar.#field, Decl(privateNameInInExpressionTransform.ts, 33, 11)) + + check(v: any) { +>check : Symbol(Bar.check, Decl(privateNameInInExpressionTransform.ts, 34, 15)) +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 35, 10)) + + #field in v; // expect Bar's 'field' WeakMap +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 35, 10)) + } +} + +function syntaxError(v: Foo) { +>syntaxError : Symbol(syntaxError, Decl(privateNameInInExpressionTransform.ts, 38, 1)) +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 40, 21)) +>Foo : Symbol(Foo, Decl(privateNameInInExpressionTransform.ts, 0, 0)) + + return #field in v; // expect `return in v` so runtime will have a syntax error +>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 40, 21)) +} + +export { } + diff --git a/tests/baselines/reference/privateNameInInExpressionTransform.types b/tests/baselines/reference/privateNameInInExpressionTransform.types new file mode 100644 index 0000000000000..5c68549be8fd4 --- /dev/null +++ b/tests/baselines/reference/privateNameInInExpressionTransform.types @@ -0,0 +1,130 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts === +class Foo { +>Foo : Foo + + #field = 1; +>#field : number +>1 : 1 + + #method() {} +>#method : () => void + + static #staticField= 2; +>#staticField : number +>2 : 2 + + static #staticMethod() {} +>#staticMethod : () => void + + check(v: any) { +>check : (v: any) => void +>v : any + + #field in v; // expect Foo's 'field' WeakMap +>#field in v : boolean +>v : any + + #method in v; // expect Foo's 'method' WeakSet +>#method in v : boolean +>v : any + + #staticField in v; // expect Foo's constructor +>#staticField in v : boolean +>v : any + + #staticMethod in v; // expect Foo's constructor +>#staticMethod in v : boolean +>v : any + } + precedence(v: any) { +>precedence : (v: any) => void +>v : any + + // '==' has lower precedence than 'in' + // '<' has same precedence than 'in' + // '<<' has higher precedence than 'in' + + v == #field in v == v; // Good precedence: ((v == (#field in v)) == v) +>v == #field in v == v : boolean +>v == #field in v : boolean +>v : any +>#field in v : boolean +>v : any +>v : any + + v << #field in v << v; // Good precedence: (v << (#field in (v << v))) +>v << #field in v << v : number +>v : any +>#field in v << v : boolean +>v << v : number +>v : any +>v : any + + v << #field in v == v; // Good precedence: ((v << (#field in v)) == v) +>v << #field in v == v : boolean +>v << #field in v : number +>v : any +>#field in v : boolean +>v : any +>v : any + + v == #field in v < v; // Good precedence: (v == ((#field in v) < v)) +>v == #field in v < v : boolean +>v : any +>#field in v < v : boolean +>#field in v : boolean +>v : any +>v : any + + #field in v && #field in v; // Good precedence: ((#field in v) && (#field in v)) +>#field in v && #field in v : boolean +>#field in v : boolean +>v : any +>#field in v : boolean +>v : Foo + } + invalidLHS(v: any) { +>invalidLHS : (v: any) => void +>v : any + + 'prop' in v = 10; +>'prop' in v : boolean +>'prop' : "prop" +>v : any +>10 : 10 + + #field in v = 10; +>#field in v : boolean +>v : any +>10 : 10 + } +} + +class Bar { +>Bar : Bar + + #field = 1; +>#field : number +>1 : 1 + + check(v: any) { +>check : (v: any) => void +>v : any + + #field in v; // expect Bar's 'field' WeakMap +>#field in v : boolean +>v : any + } +} + +function syntaxError(v: Foo) { +>syntaxError : (v: Foo) => any +>v : Foo + + return #field in v; // expect `return in v` so runtime will have a syntax error +>#field in v : any +>v : Foo +} + +export { } + diff --git a/tests/baselines/reference/privateNameInInExpressionUnused.errors.txt b/tests/baselines/reference/privateNameInInExpressionUnused.errors.txt new file mode 100644 index 0000000000000..94d56876d297b --- /dev/null +++ b/tests/baselines/reference/privateNameInInExpressionUnused.errors.txt @@ -0,0 +1,16 @@ +tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionUnused.ts(2,5): error TS6133: '#unused' is declared but its value is never read. + + +==== tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionUnused.ts (1 errors) ==== + class Foo { + #unused: undefined; // expect unused error + ~~~~~~~ +!!! error TS6133: '#unused' is declared but its value is never read. + #brand: undefined; // expect no error + + isFoo(v: any): v is Foo { + // This should count as using/reading '#brand' + return #brand in v; + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/privateNameInInExpressionUnused.js b/tests/baselines/reference/privateNameInInExpressionUnused.js new file mode 100644 index 0000000000000..651f2932d1669 --- /dev/null +++ b/tests/baselines/reference/privateNameInInExpressionUnused.js @@ -0,0 +1,22 @@ +//// [privateNameInInExpressionUnused.ts] +class Foo { + #unused: undefined; // expect unused error + #brand: undefined; // expect no error + + isFoo(v: any): v is Foo { + // This should count as using/reading '#brand' + return #brand in v; + } +} + + +//// [privateNameInInExpressionUnused.js] +"use strict"; +class Foo { + #unused; // expect unused error + #brand; // expect no error + isFoo(v) { + // This should count as using/reading '#brand' + return #brand in v; + } +} diff --git a/tests/baselines/reference/privateNameInInExpressionUnused.symbols b/tests/baselines/reference/privateNameInInExpressionUnused.symbols new file mode 100644 index 0000000000000..03c516ae887f9 --- /dev/null +++ b/tests/baselines/reference/privateNameInInExpressionUnused.symbols @@ -0,0 +1,22 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionUnused.ts === +class Foo { +>Foo : Symbol(Foo, Decl(privateNameInInExpressionUnused.ts, 0, 0)) + + #unused: undefined; // expect unused error +>#unused : Symbol(Foo.#unused, Decl(privateNameInInExpressionUnused.ts, 0, 11)) + + #brand: undefined; // expect no error +>#brand : Symbol(Foo.#brand, Decl(privateNameInInExpressionUnused.ts, 1, 23)) + + isFoo(v: any): v is Foo { +>isFoo : Symbol(Foo.isFoo, Decl(privateNameInInExpressionUnused.ts, 2, 22)) +>v : Symbol(v, Decl(privateNameInInExpressionUnused.ts, 4, 10)) +>v : Symbol(v, Decl(privateNameInInExpressionUnused.ts, 4, 10)) +>Foo : Symbol(Foo, Decl(privateNameInInExpressionUnused.ts, 0, 0)) + + // This should count as using/reading '#brand' + return #brand in v; +>v : Symbol(v, Decl(privateNameInInExpressionUnused.ts, 4, 10)) + } +} + diff --git a/tests/baselines/reference/privateNameInInExpressionUnused.types b/tests/baselines/reference/privateNameInInExpressionUnused.types new file mode 100644 index 0000000000000..74eea43e013b8 --- /dev/null +++ b/tests/baselines/reference/privateNameInInExpressionUnused.types @@ -0,0 +1,21 @@ +=== tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionUnused.ts === +class Foo { +>Foo : Foo + + #unused: undefined; // expect unused error +>#unused : undefined + + #brand: undefined; // expect no error +>#brand : undefined + + isFoo(v: any): v is Foo { +>isFoo : (v: any) => v is Foo +>v : any + + // This should count as using/reading '#brand' + return #brand in v; +>#brand in v : boolean +>v : any + } +} + diff --git a/tests/cases/conformance/classes/members/privateNames/privateNameInInExpression.ts b/tests/cases/conformance/classes/members/privateNames/privateNameInInExpression.ts new file mode 100644 index 0000000000000..abea3ed544e64 --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNameInInExpression.ts @@ -0,0 +1,113 @@ +// @strict: true +// @target: esnext +// @useDefineForClassFields: true + +class Foo { + #field = 1; + static #staticField = 2; + #method() {} + static #staticMethod() {} + + goodRhs(v: any) { + const a = #field in v; + + const b = #field in v.p1.p2; + + const c = #field in (v as {}); + + const d = #field in (v as Foo); + + const e = #field in (v as never); + + for (let f in #field in v as any) { /**/ } // unlikely but valid + } + badRhs(v: any) { + const a = #field in (v as unknown); // Bad - RHS of in must be object type or any + + const b = #fiel in v; // Bad - typo in privateID + + const c = (#field) in v; // Bad - privateID is not an expression on its own + + for (#field in v) { /**/ } // Bad - 'in' not allowed + + for (let d in #field in v) { /**/ } // Bad - rhs of in should be a object/any + } + whitespace(v: any) { + const a = v && /*0*/#field/*1*/ + /*2*/in/*3*/ + /*4*/v/*5*/ + } + flow(u: unknown, n: never, fb: Foo | Bar, fs: FooSub, b: Bar, fsb: FooSub | Bar) { + + if (typeof u === 'object') { + if (#field in n) { + n; // good n is never + } + + if (#field in u) { + u; // good u is Foo + } else { + u; // good u is object | null + } + + if (u !== null) { + if (#field in u) { + u; // good u is Foo + } else { + u; // good u is object + } + + if (#method in u) { + u; // good u is Foo + } + + if (#staticField in u) { + u; // good u is typeof Foo + } + + if (#staticMethod in u) { + u; // good u is typeof Foo + } + } + } + + if (#field in fb) { + fb; // good fb is Foo + } else { + fb; // good fb is Bar + } + + if (#field in fs) { + fs; // good fs is FooSub + } else { + fs; // good fs is never + } + + if (#field in b) { + b; // good b is 'Bar & Foo' + } else { + b; // good b is Bar + } + + if (#field in fsb) { + fsb; // good fsb is FooSub + } else { + fsb; // good fsb is Bar + } + + class Nested { + m(v: any) { + if (#field in v) { + v; // good v is Foo + } + } + } + } +} + +class FooSub extends Foo { subTypeOfFoo = true } +class Bar { notFoo = true } + +function badSyntax(v: Foo) { + return #field in v; // Bad - outside of class +} diff --git a/tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts b/tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts new file mode 100644 index 0000000000000..2518012b3e1b0 --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts @@ -0,0 +1,47 @@ +// @target: es2020 + +class Foo { + #field = 1; + #method() {} + static #staticField= 2; + static #staticMethod() {} + + check(v: any) { + #field in v; // expect Foo's 'field' WeakMap + #method in v; // expect Foo's 'method' WeakSet + #staticField in v; // expect Foo's constructor + #staticMethod in v; // expect Foo's constructor + } + precedence(v: any) { + // '==' has lower precedence than 'in' + // '<' has same precedence than 'in' + // '<<' has higher precedence than 'in' + + v == #field in v == v; // Good precedence: ((v == (#field in v)) == v) + + v << #field in v << v; // Good precedence: (v << (#field in (v << v))) + + v << #field in v == v; // Good precedence: ((v << (#field in v)) == v) + + v == #field in v < v; // Good precedence: (v == ((#field in v) < v)) + + #field in v && #field in v; // Good precedence: ((#field in v) && (#field in v)) + } + invalidLHS(v: any) { + 'prop' in v = 10; + #field in v = 10; + } +} + +class Bar { + #field = 1; + check(v: any) { + #field in v; // expect Bar's 'field' WeakMap + } +} + +function syntaxError(v: Foo) { + return #field in v; // expect `return in v` so runtime will have a syntax error +} + +export { } diff --git a/tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionUnused.ts b/tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionUnused.ts new file mode 100644 index 0000000000000..4b214a2b9e78f --- /dev/null +++ b/tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionUnused.ts @@ -0,0 +1,13 @@ +// @strict: true +// @noUnusedLocals: true +// @target: esnext + +class Foo { + #unused: undefined; // expect unused error + #brand: undefined; // expect no error + + isFoo(v: any): v is Foo { + // This should count as using/reading '#brand' + return #brand in v; + } +} diff --git a/tests/cases/fourslash/codeFixSpellingPrivateNameInIn.ts b/tests/cases/fourslash/codeFixSpellingPrivateNameInIn.ts new file mode 100644 index 0000000000000..3d3e48ede332d --- /dev/null +++ b/tests/cases/fourslash/codeFixSpellingPrivateNameInIn.ts @@ -0,0 +1,19 @@ +/// + +////class A { +//// #foo: number; +//// static isA(v: any) { +//// [|return #fo in v;|] +//// } +////} + +verify.codeFixAvailable([ + { description: "Change spelling to '#foo'" }, + { description: "Remove unused declaration for: '#foo'" }, +]); + +verify.codeFix({ + index: 0, + description: "Change spelling to '#foo'", + newRangeContent: "return #foo in v;" +}); diff --git a/tests/cases/fourslash/findAllRefsPrivateNameProperties.ts b/tests/cases/fourslash/findAllRefsPrivateNameProperties.ts index 8470772e9bf52..06c886b7e4468 100644 --- a/tests/cases/fourslash/findAllRefsPrivateNameProperties.ts +++ b/tests/cases/fourslash/findAllRefsPrivateNameProperties.ts @@ -4,6 +4,7 @@ //// [|[|{|"isDefinition": true, "isWriteAccess": true, "contextRangeIndex": 0 |}#foo|] = 10;|] //// constructor() { //// this.[|{|"isWriteAccess": true|}#foo|] = 20; +//// [|#foo|] in this; //// } ////} ////class D extends C { @@ -13,12 +14,12 @@ //// } ////} ////class E { -//// [|[|{|"isDefinition": true, "contextRangeIndex": 3 |}#foo|]: number;|] +//// [|[|{|"isDefinition": true, "contextRangeIndex": 4 |}#foo|]: number;|] //// constructor() { //// this.[|{|"isWriteAccess": true|}#foo|] = 20; //// } ////} -const [rC0Def, rC0, rC1, rE0Def, rE0, rE1] = test.ranges(); -verify.singleReferenceGroup("(property) C.#foo: number", [rC0, rC1]); +const [rC0Def, rC0, rC1, rC2, rE0Def, rE0, rE1] = test.ranges(); +verify.singleReferenceGroup("(property) C.#foo: number", [rC0, rC1, rC2]); verify.singleReferenceGroup("(property) E.#foo: number", [rE0, rE1]);