ES private field check (#44648)
* es private fields in in (#52) add support for the 'private-fields-in-in' TC39 proposal Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [fixup] include inToken when walking forEachChild(node, cb) * [squash] re-accept lib definition baseline changes * [squash] reduce if/else to ternary Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] drop 'originalName' and rename parameter instead Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] extend spelling suggestion to all privateIdentifiers Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] revert the added lexical spelling suggestions logic Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] update baseline Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] inline variable as per PR suggestion Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] test targets both esnext and es2020 as per PR comment Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * switch to using a binary expression Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] PrivateIdentifier now extends PrimaryExpression Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] accept public api baseline changes Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] classPrivateFieldInHelper now has documentation Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] type-check now follows existing in-expression path Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] parser now follows existing binaryExpression path Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] correct typo in comment Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] no longer use esNext flag Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] swap 'reciever, state' helper params Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] remove change to parenthesizerRules Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] apply suggested changes to checker Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] remove need for assertion in fixSpelling Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] improve comment hint in test Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] fix comment typos Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] add flow-test for Foo | FooSub | Bar Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] add checkExternalEmitHelpers call and new test case Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] simplify and correct parser Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] move most of the added checker logic to expression level Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] always error when privateId could not be resolved Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] reword comment Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] fix codeFixSpelling test Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] do less work Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * store symbol by priateId not binaryExpression Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * moved parsePrivateIdentifier into parsePrimaryExpression Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] checkInExpressionn bails out early on silentNeverType Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] more detailed error messages Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] resolves conflict in diagnosticMessages.json Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] update baseline for importHelpersES6 Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] remove redundent if and comment from parser Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] split up grammar/check/symbolLookup Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com> * [squash] reword message for existing left side of in-expression error Signed-off-by: Ashley Claymore <acutmore@users.noreply.github.com>
This commit is contained in:
parent
59fb3731e3
commit
af689cc5d5
|
@ -23917,6 +23917,9 @@ namespace ts {
|
|||
case SyntaxKind.InstanceOfKeyword:
|
||||
return narrowTypeByInstanceof(type, expr, assumeTrue);
|
||||
case SyntaxKind.InKeyword:
|
||||
if (isPrivateIdentifier(expr.left)) {
|
||||
return narrowTypeByPrivateIdentifierInInExpression(type, expr, assumeTrue);
|
||||
}
|
||||
const target = getReferenceCandidate(expr.right);
|
||||
const leftType = getTypeOfNode(expr.left);
|
||||
if (leftType.flags & TypeFlags.StringLiteral) {
|
||||
|
@ -23947,6 +23950,24 @@ namespace ts {
|
|||
return type;
|
||||
}
|
||||
|
||||
function narrowTypeByPrivateIdentifierInInExpression(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type {
|
||||
const target = getReferenceCandidate(expr.right);
|
||||
if (!isMatchingReference(reference, target)) {
|
||||
return type;
|
||||
}
|
||||
|
||||
Debug.assertNode(expr.left, isPrivateIdentifier);
|
||||
const symbol = getSymbolForPrivateIdentifierExpression(expr.left);
|
||||
if (symbol === undefined) {
|
||||
return type;
|
||||
}
|
||||
const classSymbol = symbol.parent!;
|
||||
const targetType = hasStaticModifier(Debug.checkDefined(symbol.valueDeclaration, "should always have a declaration"))
|
||||
? getTypeOfSymbol(classSymbol) as InterfaceType
|
||||
: getDeclaredTypeOfSymbol(classSymbol);
|
||||
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.
|
||||
|
@ -27790,6 +27811,40 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
function checkGrammarPrivateIdentifierExpression(privId: PrivateIdentifier): boolean {
|
||||
if (!getContainingClass(privId)) {
|
||||
return grammarErrorOnNode(privId, Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies);
|
||||
}
|
||||
if (!isExpressionNode(privId)) {
|
||||
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);
|
||||
}
|
||||
if (!getSymbolForPrivateIdentifierExpression(privId)) {
|
||||
return grammarErrorOnNode(privId, Diagnostics.Cannot_find_name_0, idText(privId));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function checkPrivateIdentifierExpression(privId: PrivateIdentifier): Type {
|
||||
checkGrammarPrivateIdentifierExpression(privId);
|
||||
const symbol = getSymbolForPrivateIdentifierExpression(privId);
|
||||
if (symbol) {
|
||||
markPropertyAsReferenced(symbol, /* nodeForCheckWriteOnly: */ undefined, /* isThisAccess: */ false);
|
||||
}
|
||||
return anyType;
|
||||
}
|
||||
|
||||
function getSymbolForPrivateIdentifierExpression(privId: PrivateIdentifier): Symbol | undefined {
|
||||
if (!isExpressionNode(privId)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const links = getNodeLinks(privId);
|
||||
if (links.resolvedSymbol === undefined) {
|
||||
links.resolvedSymbol = lookupSymbolForPrivateIdentifierDeclaration(privId.escapedText, privId);
|
||||
}
|
||||
return links.resolvedSymbol;
|
||||
}
|
||||
|
||||
function getPrivateIdentifierPropertyOfType(leftType: Type, lexicallyScopedIdentifier: Symbol): Symbol | undefined {
|
||||
return getPropertyOfType(leftType, lexicallyScopedIdentifier.escapedName);
|
||||
}
|
||||
|
@ -32110,11 +32165,29 @@ namespace ts {
|
|||
if (leftType === silentNeverType || rightType === silentNeverType) {
|
||||
return silentNeverType;
|
||||
}
|
||||
leftType = checkNonNullType(leftType, left);
|
||||
if (isPrivateIdentifier(left)) {
|
||||
if (languageVersion < ScriptTarget.ESNext) {
|
||||
checkExternalEmitHelpers(left, ExternalEmitHelpers.ClassPrivateFieldIn);
|
||||
}
|
||||
// Unlike in 'checkPrivateIdentifierExpression' we now have access to the RHS type
|
||||
// which provides us with the opportunity to emit more detailed errors
|
||||
if (!getNodeLinks(left).resolvedSymbol && getContainingClass(left)) {
|
||||
const isUncheckedJS = isUncheckedJSSuggestion(left, rightType.symbol, /*excludeClasses*/ true);
|
||||
reportNonexistentProperty(left, rightType, isUncheckedJS);
|
||||
}
|
||||
}
|
||||
else {
|
||||
leftType = checkNonNullType(leftType, left);
|
||||
// TypeScript 1.0 spec (April 2014): 4.15.5
|
||||
// Require the left operand to be of type Any, the String primitive type, or the Number primitive type.
|
||||
if (!(allTypesAssignableToKind(leftType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbolLike) ||
|
||||
isTypeAssignableToKind(leftType, TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping | TypeFlags.TypeParameter))) {
|
||||
error(left, Diagnostics.The_left_hand_side_of_an_in_expression_must_be_a_private_identifier_or_of_type_any_string_number_or_symbol);
|
||||
}
|
||||
}
|
||||
rightType = checkNonNullType(rightType, right);
|
||||
// TypeScript 1.0 spec (April 2014): 4.15.5
|
||||
// The in operator requires the left operand to be of type Any, the String primitive type, or the Number primitive type,
|
||||
// and the right operand to be
|
||||
// The in operator requires the right operand to be
|
||||
//
|
||||
// 1. assignable to the non-primitive type,
|
||||
// 2. an unconstrained type parameter,
|
||||
|
@ -32132,10 +32205,6 @@ namespace ts {
|
|||
// unless *all* instantiations would result in an error.
|
||||
//
|
||||
// The result is always of the Boolean primitive type.
|
||||
if (!(allTypesAssignableToKind(leftType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbolLike) ||
|
||||
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);
|
||||
}
|
||||
const rightTypeConstraint = getConstraintOfType(rightType);
|
||||
if (!allTypesAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive) ||
|
||||
rightTypeConstraint && (
|
||||
|
@ -33517,6 +33586,8 @@ namespace ts {
|
|||
switch (kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
return checkIdentifier(node as Identifier, checkMode);
|
||||
case SyntaxKind.PrivateIdentifier:
|
||||
return checkPrivateIdentifierExpression(node as PrivateIdentifier);
|
||||
case SyntaxKind.ThisKeyword:
|
||||
return checkThisExpression(node);
|
||||
case SyntaxKind.SuperKeyword:
|
||||
|
@ -40296,6 +40367,9 @@ namespace ts {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
else if (isPrivateIdentifier(name)) {
|
||||
return getSymbolForPrivateIdentifierExpression(name);
|
||||
}
|
||||
else if (name.kind === SyntaxKind.PropertyAccessExpression || name.kind === SyntaxKind.QualifiedName) {
|
||||
const links = getNodeLinks(name);
|
||||
if (links.resolvedSymbol) {
|
||||
|
@ -41712,6 +41786,7 @@ namespace ts {
|
|||
case ExternalEmitHelpers.MakeTemplateObject: return "__makeTemplateObject";
|
||||
case ExternalEmitHelpers.ClassPrivateFieldGet: return "__classPrivateFieldGet";
|
||||
case ExternalEmitHelpers.ClassPrivateFieldSet: return "__classPrivateFieldSet";
|
||||
case ExternalEmitHelpers.ClassPrivateFieldIn: return "__classPrivateFieldIn";
|
||||
case ExternalEmitHelpers.CreateBinding: return "__createBinding";
|
||||
default: return Debug.fail("Unrecognized helper");
|
||||
}
|
||||
|
|
|
@ -1392,6 +1392,10 @@
|
|||
"category": "Message",
|
||||
"code": 1450
|
||||
},
|
||||
"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": {
|
||||
"category": "Error",
|
||||
"code": 1451
|
||||
},
|
||||
|
||||
"The types of '{0}' are incompatible between these types.": {
|
||||
"category": "Error",
|
||||
|
@ -1654,7 +1658,7 @@
|
|||
"category": "Error",
|
||||
"code": 2359
|
||||
},
|
||||
"The left-hand side of an 'in' expression must be of type 'any', 'string', 'number', or 'symbol'.": {
|
||||
"The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.": {
|
||||
"category": "Error",
|
||||
"code": 2360
|
||||
},
|
||||
|
|
|
@ -1684,6 +1684,8 @@ namespace ts {
|
|||
// Identifiers
|
||||
case SyntaxKind.Identifier:
|
||||
return emitIdentifier(node as Identifier);
|
||||
case SyntaxKind.PrivateIdentifier:
|
||||
return emitPrivateIdentifier(node as PrivateIdentifier);
|
||||
|
||||
// Expressions
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
|
|
|
@ -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(state: Identifier, receiver: Expression): Expression;
|
||||
}
|
||||
|
||||
export function createEmitHelperFactory(context: TransformationContext): EmitHelperFactory {
|
||||
|
@ -75,6 +76,7 @@ namespace ts {
|
|||
// Class Fields Helpers
|
||||
createClassPrivateFieldGetHelper,
|
||||
createClassPrivateFieldSetHelper,
|
||||
createClassPrivateFieldInHelper
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -395,6 +397,10 @@ namespace ts {
|
|||
return factory.createCallExpression(getUnscopedHelperName("__classPrivateFieldSet"), /*typeArguments*/ undefined, args);
|
||||
}
|
||||
|
||||
function createClassPrivateFieldInHelper(state: Identifier, receiver: Expression) {
|
||||
context.requestEmitHelper(classPrivateFieldInHelper);
|
||||
return factory.createCallExpression(getUnscopedHelperName("__classPrivateFieldIn"), /* typeArguments*/ undefined, [state, receiver]);
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
@ -961,6 +967,29 @@ namespace ts {
|
|||
};`
|
||||
};
|
||||
|
||||
/**
|
||||
* Parameters:
|
||||
* @param state — One of the following:
|
||||
* - A WeakMap when the member is a private instance field.
|
||||
* - A WeakSet when the member is a private instance method or accessor.
|
||||
* - A function value that should be the undecorated class constructor when the member is a private static field, method, or accessor.
|
||||
* @param receiver — The object being checked if it has the private member.
|
||||
*
|
||||
* Usage:
|
||||
* This helper is used to transform `#field in expression` to
|
||||
* `__classPrivateFieldIn(<weakMap/weakSet/constructor>, expression)`
|
||||
*/
|
||||
export const classPrivateFieldInHelper: UnscopedEmitHelper = {
|
||||
name: "typescript:classPrivateFieldIn",
|
||||
importName: "__classPrivateFieldIn",
|
||||
scoped: false,
|
||||
text: `
|
||||
var __classPrivateFieldIn = (this && this.__classPrivateFieldIn) || function(state, receiver) {
|
||||
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<string, UnscopedEmitHelper> | undefined;
|
||||
|
||||
export function getAllUnscopedEmitHelpers() {
|
||||
|
@ -986,6 +1015,7 @@ namespace ts {
|
|||
exportStarHelper,
|
||||
classPrivateFieldGetHelper,
|
||||
classPrivateFieldSetHelper,
|
||||
classPrivateFieldInHelper,
|
||||
createBindingHelper,
|
||||
setModuleDefaultHelper
|
||||
], helper => helper.name));
|
||||
|
|
|
@ -452,4 +452,4 @@ namespace ts {
|
|||
parenthesizeConstituentTypesOfUnionOrIntersectionType: nodes => cast(nodes, isNodeArray),
|
||||
parenthesizeTypeArguments: nodes => nodes && cast(nodes, isNodeArray),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5617,6 +5617,8 @@ namespace ts {
|
|||
break;
|
||||
case SyntaxKind.TemplateHead:
|
||||
return parseTemplateExpression(/* isTaggedTemplate */ false);
|
||||
case SyntaxKind.PrivateIdentifier:
|
||||
return parsePrivateIdentifier();
|
||||
}
|
||||
|
||||
return parseIdentifier(Diagnostics.Expression_expected);
|
||||
|
|
|
@ -266,15 +266,44 @@ namespace ts {
|
|||
|
||||
/**
|
||||
* If we visit a private name, this means it is an undeclared private name.
|
||||
* Replace it with an empty identifier to indicate a problem with the code.
|
||||
* Replace it with an empty identifier to indicate a problem with the code,
|
||||
* unless we are in a statement position - otherwise this will not trigger
|
||||
* a SyntaxError.
|
||||
*/
|
||||
function visitPrivateIdentifier(node: PrivateIdentifier) {
|
||||
if (!shouldTransformPrivateElementsOrClassStaticBlocks) {
|
||||
return node;
|
||||
}
|
||||
if (isStatement(node.parent)) {
|
||||
return node;
|
||||
}
|
||||
return setOriginalNode(factory.createIdentifier(""), node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits `#id in expr`
|
||||
*/
|
||||
function visitPrivateIdentifierInInExpression(node: BinaryExpression) {
|
||||
if (!shouldTransformPrivateElementsOrClassStaticBlocks) {
|
||||
return node;
|
||||
}
|
||||
const privId = node.left;
|
||||
Debug.assertNode(privId, isPrivateIdentifier);
|
||||
Debug.assert(node.operatorToken.kind === SyntaxKind.InKeyword);
|
||||
const info = accessPrivateIdentifier(privId);
|
||||
if (info) {
|
||||
const receiver = visitNode(node.right, visitor, isExpression);
|
||||
|
||||
return setOriginalNode(
|
||||
context.getEmitHelperFactory().createClassPrivateFieldInHelper(info.brandCheckIdentifier, receiver),
|
||||
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.
|
||||
*
|
||||
|
@ -827,6 +856,9 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (node.operatorToken.kind === SyntaxKind.InKeyword && isPrivateIdentifier(node.left)) {
|
||||
return visitPrivateIdentifierInInExpression(node);
|
||||
}
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
|
|
|
@ -1214,7 +1214,8 @@ namespace ts {
|
|||
readonly expression: Expression;
|
||||
}
|
||||
|
||||
export interface PrivateIdentifier extends Node {
|
||||
// Typed as a PrimaryExpression due to its presence in BinaryExpressions (#field in expr)
|
||||
export interface PrivateIdentifier extends PrimaryExpression {
|
||||
readonly kind: SyntaxKind.PrivateIdentifier;
|
||||
// escaping not strictly necessary
|
||||
// avoids gotchas in transforms and utils
|
||||
|
@ -6854,7 +6855,8 @@ namespace ts {
|
|||
MakeTemplateObject = 1 << 18, // __makeTemplateObject (used for constructing template string array objects)
|
||||
ClassPrivateFieldGet = 1 << 19, // __classPrivateFieldGet (used by the class private field transformation)
|
||||
ClassPrivateFieldSet = 1 << 20, // __classPrivateFieldSet (used by the class private field transformation)
|
||||
CreateBinding = 1 << 21, // __createBinding (use by the module transform for (re)exports and namespace imports)
|
||||
ClassPrivateFieldIn = 1 << 21, // __classPrivateFieldIn (used by the class private field transformation)
|
||||
CreateBinding = 1 << 22, // __createBinding (use by the module transform for (re)exports and namespace imports)
|
||||
FirstEmitHelper = Extends,
|
||||
LastEmitHelper = CreateBinding,
|
||||
|
||||
|
|
|
@ -1949,6 +1949,8 @@ namespace ts {
|
|||
node = node.parent;
|
||||
}
|
||||
return node.parent.kind === SyntaxKind.TypeQuery || isJSDocLinkLike(node.parent) || isJSDocNameReference(node.parent) || isJSDocMemberName(node.parent) || isJSXTagName(node);
|
||||
case SyntaxKind.PrivateIdentifier:
|
||||
return isBinaryExpression(node.parent) && node.parent.left === node && node.parent.operatorToken.kind === SyntaxKind.InKeyword;
|
||||
case SyntaxKind.Identifier:
|
||||
if (node.parent.kind === SyntaxKind.TypeQuery || isJSDocLinkLike(node.parent) || isJSDocNameReference(node.parent) || isJSDocMemberName(node.parent) || isJSXTagName(node)) {
|
||||
return true;
|
||||
|
@ -3706,6 +3708,7 @@ namespace ts {
|
|||
case SyntaxKind.ThisKeyword:
|
||||
case SyntaxKind.SuperKeyword:
|
||||
case SyntaxKind.Identifier:
|
||||
case SyntaxKind.PrivateIdentifier:
|
||||
case SyntaxKind.NullKeyword:
|
||||
case SyntaxKind.TrueKeyword:
|
||||
case SyntaxKind.FalseKeyword:
|
||||
|
|
|
@ -1516,6 +1516,7 @@ namespace ts {
|
|||
case SyntaxKind.ClassExpression:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.Identifier:
|
||||
case SyntaxKind.PrivateIdentifier: // technically this is only an Expression if it's in a `#field in expr` BinaryExpression
|
||||
case SyntaxKind.RegularExpressionLiteral:
|
||||
case SyntaxKind.NumericLiteral:
|
||||
case SyntaxKind.BigIntLiteral:
|
||||
|
|
|
@ -4,7 +4,7 @@ namespace ts.codefix {
|
|||
const didYouMeanStaticMemberCode = Diagnostics.Cannot_find_name_0_Did_you_mean_the_static_member_1_0.code;
|
||||
const errorCodes = [
|
||||
Diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0.code,
|
||||
Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies.code,
|
||||
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.code,
|
||||
didYouMeanStaticMemberCode,
|
||||
];
|
||||
registerCodeFix({
|
||||
|
@ -32,7 +32,7 @@ namespace ts.codefix {
|
|||
|
||||
function getInfo(sourceFile: SourceFile, pos: number, diagCode: number): Info | undefined {
|
||||
const node = getTokenAtPosition(sourceFile, pos);
|
||||
if (isIdentifier(node)) {
|
||||
if (isIdentifier(node) || isPrivateIdentifier(node)) {
|
||||
return { node, className: diagCode === didYouMeanStaticMemberCode ? getContainingClass(node)!.name!.text : undefined };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,6 +57,10 @@ namespace ts.codefix {
|
|||
}
|
||||
suggestedSymbol = checker.getSuggestedSymbolForNonexistentProperty(node, containingType);
|
||||
}
|
||||
else if (isBinaryExpression(parent) && parent.operatorToken.kind === SyntaxKind.InKeyword && parent.left === node && isPrivateIdentifier(node)) {
|
||||
const receiverType = checker.getTypeAtLocation(parent.right);
|
||||
suggestedSymbol = checker.getSuggestedSymbolForNonexistentProperty(node, receiverType);
|
||||
}
|
||||
else if (isQualifiedName(parent) && parent.right === node) {
|
||||
const symbol = checker.getSymbolAtLocation(parent.left);
|
||||
if (symbol && symbol.flags & SymbolFlags.Module) {
|
||||
|
|
|
@ -401,6 +401,12 @@ namespace ts {
|
|||
public kind!: SyntaxKind.PrivateIdentifier;
|
||||
public escapedText!: __String;
|
||||
public symbol!: Symbol;
|
||||
_primaryExpressionBrand: any;
|
||||
_memberExpressionBrand: any;
|
||||
_leftHandSideExpressionBrand: any;
|
||||
_updateExpressionBrand: any;
|
||||
_unaryExpressionBrand: any;
|
||||
_expressionBrand: any;
|
||||
constructor(_kind: SyntaxKind.PrivateIdentifier, pos: number, end: number) {
|
||||
super(pos, end);
|
||||
}
|
||||
|
|
|
@ -670,7 +670,7 @@ declare namespace ts {
|
|||
readonly parent: Declaration;
|
||||
readonly expression: Expression;
|
||||
}
|
||||
export interface PrivateIdentifier extends Node {
|
||||
export interface PrivateIdentifier extends PrimaryExpression {
|
||||
readonly kind: SyntaxKind.PrivateIdentifier;
|
||||
readonly escapedText: __String;
|
||||
}
|
||||
|
|
|
@ -670,7 +670,7 @@ declare namespace ts {
|
|||
readonly parent: Declaration;
|
||||
readonly expression: Expression;
|
||||
}
|
||||
export interface PrivateIdentifier extends Node {
|
||||
export interface PrivateIdentifier extends PrimaryExpression {
|
||||
readonly kind: SyntaxKind.PrivateIdentifier;
|
||||
readonly escapedText: __String;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ declare var dec: any;
|
|||
@dec export class A {
|
||||
#x: number = 1;
|
||||
async f() { this.#x = await this.#x; }
|
||||
g(u) { return #x in u; }
|
||||
}
|
||||
|
||||
const o = { a: 1 };
|
||||
|
@ -18,11 +19,12 @@ export declare function __metadata(metadataKey: any, metadataValue: any): Functi
|
|||
export declare function __awaiter(thisArg: any, _arguments: any, P: Function, generator: Function): any;
|
||||
export declare function __classPrivateFieldGet(a: any, b: any, c: any, d: any): any;
|
||||
export declare function __classPrivateFieldSet(a: any, b: any, c: any, d: any, e: any): any;
|
||||
export declare function __classPrivateFieldIn(a: any, b: any): boolean;
|
||||
|
||||
|
||||
//// [a.js]
|
||||
var _A_x;
|
||||
import { __awaiter, __classPrivateFieldGet, __classPrivateFieldSet, __decorate } from "tslib";
|
||||
import { __awaiter, __classPrivateFieldGet, __classPrivateFieldIn, __classPrivateFieldSet, __decorate } from "tslib";
|
||||
let A = class A {
|
||||
constructor() {
|
||||
_A_x.set(this, 1);
|
||||
|
@ -30,6 +32,7 @@ let A = class A {
|
|||
f() {
|
||||
return __awaiter(this, void 0, void 0, function* () { __classPrivateFieldSet(this, _A_x, yield __classPrivateFieldGet(this, _A_x, "f"), "f"); });
|
||||
}
|
||||
g(u) { return __classPrivateFieldIn(_A_x, u); }
|
||||
};
|
||||
_A_x = new WeakMap();
|
||||
A = __decorate([
|
||||
|
|
|
@ -15,15 +15,21 @@ declare var dec: any;
|
|||
>this : Symbol(A, Decl(a.ts, 0, 21))
|
||||
>this.#x : Symbol(A.#x, Decl(a.ts, 1, 21))
|
||||
>this : Symbol(A, Decl(a.ts, 0, 21))
|
||||
|
||||
g(u) { return #x in u; }
|
||||
>g : Symbol(A.g, Decl(a.ts, 3, 42))
|
||||
>u : Symbol(u, Decl(a.ts, 4, 6))
|
||||
>#x : Symbol(A.#x, Decl(a.ts, 1, 21))
|
||||
>u : Symbol(u, Decl(a.ts, 4, 6))
|
||||
}
|
||||
|
||||
const o = { a: 1 };
|
||||
>o : Symbol(o, Decl(a.ts, 6, 5))
|
||||
>a : Symbol(a, Decl(a.ts, 6, 11))
|
||||
>o : Symbol(o, Decl(a.ts, 7, 5))
|
||||
>a : Symbol(a, Decl(a.ts, 7, 11))
|
||||
|
||||
const y = { ...o };
|
||||
>y : Symbol(y, Decl(a.ts, 7, 5))
|
||||
>o : Symbol(o, Decl(a.ts, 6, 5))
|
||||
>y : Symbol(y, Decl(a.ts, 8, 5))
|
||||
>o : Symbol(o, Decl(a.ts, 7, 5))
|
||||
|
||||
=== tests/cases/compiler/tslib.d.ts ===
|
||||
export declare function __extends(d: Function, b: Function): void;
|
||||
|
@ -78,3 +84,8 @@ export declare function __classPrivateFieldSet(a: any, b: any, c: any, d: any, e
|
|||
>d : Symbol(d, Decl(tslib.d.ts, --, --))
|
||||
>e : Symbol(e, Decl(tslib.d.ts, --, --))
|
||||
|
||||
export declare function __classPrivateFieldIn(a: any, b: any): boolean;
|
||||
>__classPrivateFieldIn : Symbol(__classPrivateFieldIn, Decl(tslib.d.ts, --, --))
|
||||
>a : Symbol(a, Decl(tslib.d.ts, --, --))
|
||||
>b : Symbol(b, Decl(tslib.d.ts, --, --))
|
||||
|
||||
|
|
|
@ -18,6 +18,13 @@ declare var dec: any;
|
|||
>await this.#x : number
|
||||
>this.#x : number
|
||||
>this : this
|
||||
|
||||
g(u) { return #x in u; }
|
||||
>g : (u: any) => boolean
|
||||
>u : any
|
||||
>#x in u : boolean
|
||||
>#x : any
|
||||
>u : any
|
||||
}
|
||||
|
||||
const o = { a: 1 };
|
||||
|
@ -76,3 +83,8 @@ export declare function __classPrivateFieldSet(a: any, b: any, c: any, d: any, e
|
|||
>d : any
|
||||
>e : any
|
||||
|
||||
export declare function __classPrivateFieldIn(a: any, b: any): boolean;
|
||||
>__classPrivateFieldIn : (a: any, b: any) => boolean
|
||||
>a : any
|
||||
>b : any
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
tests/cases/compiler/main.ts(4,9): error TS2343: This syntax requires an imported helper named '__classPrivateFieldSet' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'.
|
||||
tests/cases/compiler/main.ts(4,23): error TS2343: This syntax requires an imported helper named '__classPrivateFieldGet' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'.
|
||||
tests/cases/compiler/main.ts(5,9): error TS2343: This syntax requires an imported helper named '__classPrivateFieldIn' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/main.ts (3 errors) ====
|
||||
export class Foo {
|
||||
#field = true;
|
||||
f() {
|
||||
this.#field = this.#field;
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2343: This syntax requires an imported helper named '__classPrivateFieldSet' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'.
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2343: This syntax requires an imported helper named '__classPrivateFieldGet' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'.
|
||||
#field in this;
|
||||
~~~~~~
|
||||
!!! error TS2343: This syntax requires an imported helper named '__classPrivateFieldIn' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'.
|
||||
}
|
||||
}
|
||||
|
||||
==== tests/cases/compiler/tslib.d.ts (0 errors) ====
|
||||
export {}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
//// [tests/cases/compiler/importHelpersNoHelpersForPrivateFields.ts] ////
|
||||
|
||||
//// [main.ts]
|
||||
export class Foo {
|
||||
#field = true;
|
||||
f() {
|
||||
this.#field = this.#field;
|
||||
#field in this;
|
||||
}
|
||||
}
|
||||
|
||||
//// [tslib.d.ts]
|
||||
export {}
|
||||
|
||||
|
||||
//// [main.js]
|
||||
"use strict";
|
||||
var _Foo_field;
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Foo = void 0;
|
||||
const tslib_1 = require("tslib");
|
||||
class Foo {
|
||||
constructor() {
|
||||
_Foo_field.set(this, true);
|
||||
}
|
||||
f() {
|
||||
(0, tslib_1.__classPrivateFieldSet)(this, _Foo_field, (0, tslib_1.__classPrivateFieldGet)(this, _Foo_field, "f"), "f");
|
||||
(0, tslib_1.__classPrivateFieldIn)(_Foo_field, this);
|
||||
}
|
||||
}
|
||||
exports.Foo = Foo;
|
||||
_Foo_field = new WeakMap();
|
|
@ -0,0 +1,26 @@
|
|||
=== tests/cases/compiler/main.ts ===
|
||||
export class Foo {
|
||||
>Foo : Symbol(Foo, Decl(main.ts, 0, 0))
|
||||
|
||||
#field = true;
|
||||
>#field : Symbol(Foo.#field, Decl(main.ts, 0, 18))
|
||||
|
||||
f() {
|
||||
>f : Symbol(Foo.f, Decl(main.ts, 1, 18))
|
||||
|
||||
this.#field = this.#field;
|
||||
>this.#field : Symbol(Foo.#field, Decl(main.ts, 0, 18))
|
||||
>this : Symbol(Foo, Decl(main.ts, 0, 0))
|
||||
>this.#field : Symbol(Foo.#field, Decl(main.ts, 0, 18))
|
||||
>this : Symbol(Foo, Decl(main.ts, 0, 0))
|
||||
|
||||
#field in this;
|
||||
>#field : Symbol(Foo.#field, Decl(main.ts, 0, 18))
|
||||
>this : Symbol(Foo, Decl(main.ts, 0, 0))
|
||||
}
|
||||
}
|
||||
|
||||
=== tests/cases/compiler/tslib.d.ts ===
|
||||
export {}
|
||||
No type information for this code.
|
||||
No type information for this code.
|
|
@ -0,0 +1,29 @@
|
|||
=== tests/cases/compiler/main.ts ===
|
||||
export class Foo {
|
||||
>Foo : Foo
|
||||
|
||||
#field = true;
|
||||
>#field : boolean
|
||||
>true : true
|
||||
|
||||
f() {
|
||||
>f : () => void
|
||||
|
||||
this.#field = this.#field;
|
||||
>this.#field = this.#field : boolean
|
||||
>this.#field : boolean
|
||||
>this : this
|
||||
>this.#field : boolean
|
||||
>this : this
|
||||
|
||||
#field in this;
|
||||
>#field in this : boolean
|
||||
>#field : any
|
||||
>this : this
|
||||
}
|
||||
}
|
||||
|
||||
=== tests/cases/compiler/tslib.d.ts ===
|
||||
export {}
|
||||
No type information for this code.
|
||||
No type information for this code.
|
|
@ -1,12 +1,12 @@
|
|||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(15,11): error TS2360: The left-hand side of an 'in' expression must be of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(16,11): error TS2360: The left-hand side of an 'in' expression must be of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(17,11): error TS2360: The left-hand side of an 'in' expression must be of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(15,11): error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(16,11): error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(17,11): error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(19,11): error TS2531: Object is possibly 'null'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(20,11): error TS2532: Object is possibly 'undefined'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(22,11): error TS2360: The left-hand side of an 'in' expression must be of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(23,11): error TS2360: The left-hand side of an 'in' expression must be of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(24,12): error TS2360: The left-hand side of an 'in' expression must be of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(25,12): error TS2360: The left-hand side of an 'in' expression must be of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(22,11): error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(23,11): error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(24,12): error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(25,12): error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(35,16): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(36,16): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(37,16): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
|
@ -17,7 +17,7 @@ tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInv
|
|||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(42,16): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(43,16): error TS2531: Object is possibly 'null'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(44,17): error TS2532: Object is possibly 'undefined'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(47,11): error TS2360: The left-hand side of an 'in' expression must be of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(47,11): error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(47,17): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
|
||||
|
||||
|
@ -38,13 +38,13 @@ tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInv
|
|||
|
||||
var ra1 = a1 in x;
|
||||
~~
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be of type 'any', 'string', 'number', or 'symbol'.
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
var ra2 = a2 in x;
|
||||
~~
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be of type 'any', 'string', 'number', or 'symbol'.
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
var ra3 = a3 in x;
|
||||
~~
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be of type 'any', 'string', 'number', or 'symbol'.
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
var ra4 = a4 in x;
|
||||
var ra5 = null in x;
|
||||
~~~~
|
||||
|
@ -55,16 +55,16 @@ tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInv
|
|||
var ra7 = E.a in x;
|
||||
var ra8 = false in x;
|
||||
~~~~~
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be of type 'any', 'string', 'number', or 'symbol'.
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
var ra9 = {} in x;
|
||||
~~
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be of type 'any', 'string', 'number', or 'symbol'.
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
var ra10 = a5 in x;
|
||||
~~
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be of type 'any', 'string', 'number', or 'symbol'.
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
var ra11 = a6 in x;
|
||||
~~
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be of type 'any', 'string', 'number', or 'symbol'.
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
|
||||
// invalid right operands
|
||||
// the right operand is required to be of type Any, an object type, or a type parameter type
|
||||
|
@ -108,6 +108,6 @@ tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInv
|
|||
// both operands are invalid
|
||||
var rc1 = {} in '';
|
||||
~~
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be of type 'any', 'string', 'number', or 'symbol'.
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
|
@ -1,15 +1,12 @@
|
|||
tests/cases/conformance/classes/members/privateNames/privateNameHashCharName.ts(1,1): error TS1127: Invalid character.
|
||||
tests/cases/conformance/classes/members/privateNames/privateNameHashCharName.ts(1,1): error TS2304: Cannot find name '#'.
|
||||
tests/cases/conformance/classes/members/privateNames/privateNameHashCharName.ts(4,5): error TS1127: Invalid character.
|
||||
tests/cases/conformance/classes/members/privateNames/privateNameHashCharName.ts(7,14): error TS1127: Invalid character.
|
||||
|
||||
|
||||
==== tests/cases/conformance/classes/members/privateNames/privateNameHashCharName.ts (4 errors) ====
|
||||
==== tests/cases/conformance/classes/members/privateNames/privateNameHashCharName.ts (3 errors) ====
|
||||
#
|
||||
~
|
||||
!!! error TS1127: Invalid character.
|
||||
~
|
||||
!!! error TS2304: Cannot find name '#'.
|
||||
|
||||
class C {
|
||||
#
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
=== tests/cases/conformance/classes/members/privateNames/privateNameHashCharName.ts ===
|
||||
#
|
||||
># : any
|
||||
|
||||
class C {
|
||||
>C : C
|
||||
|
|
146
tests/baselines/reference/privateNameInInExpression.errors.txt
Normal file
146
tests/baselines/reference/privateNameInInExpression.errors.txt
Normal file
|
@ -0,0 +1,146 @@
|
|||
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 TS2304: Cannot find name '#fiel'.
|
||||
tests/cases/conformance/classes/members/privateNames/privateNameInInExpression.ts(23,19): error TS2339: Property '#fiel' does not exist on type 'any'.
|
||||
tests/cases/conformance/classes/members/privateNames/privateNameInInExpression.ts(25,20): error TS1451: 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
|
||||
tests/cases/conformance/classes/members/privateNames/privateNameInInExpression.ts(27,14): error TS1451: 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
|
||||
tests/cases/conformance/classes/members/privateNames/privateNameInInExpression.ts(27,14): error TS2406: The left-hand side of a 'for...in' statement must be a variable or a property access.
|
||||
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(114,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 TS2304: Cannot find name '#fiel'.
|
||||
~~~~~
|
||||
!!! error TS2339: Property '#fiel' does not exist on type 'any'.
|
||||
|
||||
const c = (#field) in v; // Bad - privateID is not an expression on its own
|
||||
~~~~~~
|
||||
!!! error TS1451: 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
|
||||
|
||||
for (#field in v) { /**/ } // Bad - 'in' not allowed
|
||||
~~~~~~
|
||||
!!! error TS1451: 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
|
||||
~~~~~~
|
||||
!!! error TS2406: The left-hand side of a 'for...in' statement must be a variable or a property access.
|
||||
|
||||
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, fsfb: Foo | 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
|
||||
}
|
||||
|
||||
if (#field in fsfb) {
|
||||
fsfb; // good fsfb is 'Foo | FooSub'
|
||||
} else {
|
||||
fsfb; // good fsfb 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.
|
||||
}
|
||||
|
222
tests/baselines/reference/privateNameInInExpression.js
Normal file
222
tests/baselines/reference/privateNameInInExpression.js
Normal file
|
@ -0,0 +1,222 @@
|
|||
//// [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, fsfb: Foo | 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
|
||||
}
|
||||
|
||||
if (#field in fsfb) {
|
||||
fsfb; // good fsfb is 'Foo | FooSub'
|
||||
} else {
|
||||
fsfb; // good fsfb 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, fsfb) {
|
||||
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
|
||||
}
|
||||
if (#field in fsfb) {
|
||||
fsfb; // good fsfb is 'Foo | FooSub'
|
||||
}
|
||||
else {
|
||||
fsfb; // good fsfb 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
|
||||
}
|
269
tests/baselines/reference/privateNameInInExpression.symbols
Normal file
269
tests/baselines/reference/privateNameInInExpression.symbols
Normal file
|
@ -0,0 +1,269 @@
|
|||
=== 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))
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpression.ts, 0, 11))
|
||||
>v : Symbol(v, Decl(privateNameInInExpression.ts, 6, 12))
|
||||
|
||||
const b = #field in v.p1.p2;
|
||||
>b : Symbol(b, Decl(privateNameInInExpression.ts, 9, 13))
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpression.ts, 0, 11))
|
||||
>v : Symbol(v, Decl(privateNameInInExpression.ts, 6, 12))
|
||||
|
||||
const c = #field in (v as {});
|
||||
>c : Symbol(c, Decl(privateNameInInExpression.ts, 11, 13))
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpression.ts, 0, 11))
|
||||
>v : Symbol(v, Decl(privateNameInInExpression.ts, 6, 12))
|
||||
|
||||
const d = #field in (v as Foo);
|
||||
>d : Symbol(d, Decl(privateNameInInExpression.ts, 13, 13))
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpression.ts, 0, 11))
|
||||
>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))
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpression.ts, 0, 11))
|
||||
>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))
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpression.ts, 0, 11))
|
||||
>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))
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpression.ts, 0, 11))
|
||||
>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))
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpression.ts, 0, 11))
|
||||
>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))
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpression.ts, 0, 11))
|
||||
|
||||
/*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, fsfb: Foo | 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, 109, 48))
|
||||
>fs : Symbol(fs, Decl(privateNameInInExpression.ts, 35, 45))
|
||||
>FooSub : Symbol(FooSub, Decl(privateNameInInExpression.ts, 107, 1))
|
||||
>b : Symbol(b, Decl(privateNameInInExpression.ts, 35, 57))
|
||||
>Bar : Symbol(Bar, Decl(privateNameInInExpression.ts, 109, 48))
|
||||
>fsb : Symbol(fsb, Decl(privateNameInInExpression.ts, 35, 65))
|
||||
>FooSub : Symbol(FooSub, Decl(privateNameInInExpression.ts, 107, 1))
|
||||
>Bar : Symbol(Bar, Decl(privateNameInInExpression.ts, 109, 48))
|
||||
>fsfb : Symbol(fsfb, Decl(privateNameInInExpression.ts, 35, 84))
|
||||
>Foo : Symbol(Foo, Decl(privateNameInInExpression.ts, 0, 0))
|
||||
>FooSub : Symbol(FooSub, Decl(privateNameInInExpression.ts, 107, 1))
|
||||
>Bar : Symbol(Bar, Decl(privateNameInInExpression.ts, 109, 48))
|
||||
|
||||
if (typeof u === 'object') {
|
||||
>u : Symbol(u, Decl(privateNameInInExpression.ts, 35, 9))
|
||||
|
||||
if (#field in n) {
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpression.ts, 0, 11))
|
||||
>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) {
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpression.ts, 0, 11))
|
||||
>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) {
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpression.ts, 0, 11))
|
||||
>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) {
|
||||
>#method : Symbol(Foo.#method, Decl(privateNameInInExpression.ts, 2, 28))
|
||||
>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) {
|
||||
>#staticField : Symbol(Foo.#staticField, Decl(privateNameInInExpression.ts, 1, 15))
|
||||
>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) {
|
||||
>#staticMethod : Symbol(Foo.#staticMethod, Decl(privateNameInInExpression.ts, 3, 16))
|
||||
>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) {
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpression.ts, 0, 11))
|
||||
>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) {
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpression.ts, 0, 11))
|
||||
>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) {
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpression.ts, 0, 11))
|
||||
>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) {
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpression.ts, 0, 11))
|
||||
>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))
|
||||
}
|
||||
|
||||
if (#field in fsfb) {
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpression.ts, 0, 11))
|
||||
>fsfb : Symbol(fsfb, Decl(privateNameInInExpression.ts, 35, 84))
|
||||
|
||||
fsfb; // good fsfb is 'Foo | FooSub'
|
||||
>fsfb : Symbol(fsfb, Decl(privateNameInInExpression.ts, 35, 84))
|
||||
|
||||
} else {
|
||||
fsfb; // good fsfb is Bar
|
||||
>fsfb : Symbol(fsfb, Decl(privateNameInInExpression.ts, 35, 84))
|
||||
}
|
||||
|
||||
class Nested {
|
||||
>Nested : Symbol(Nested, Decl(privateNameInInExpression.ts, 97, 9))
|
||||
|
||||
m(v: any) {
|
||||
>m : Symbol(Nested.m, Decl(privateNameInInExpression.ts, 99, 22))
|
||||
>v : Symbol(v, Decl(privateNameInInExpression.ts, 100, 14))
|
||||
|
||||
if (#field in v) {
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpression.ts, 0, 11))
|
||||
>v : Symbol(v, Decl(privateNameInInExpression.ts, 100, 14))
|
||||
|
||||
v; // good v is Foo
|
||||
>v : Symbol(v, Decl(privateNameInInExpression.ts, 100, 14))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FooSub extends Foo { subTypeOfFoo = true }
|
||||
>FooSub : Symbol(FooSub, Decl(privateNameInInExpression.ts, 107, 1))
|
||||
>Foo : Symbol(Foo, Decl(privateNameInInExpression.ts, 0, 0))
|
||||
>subTypeOfFoo : Symbol(FooSub.subTypeOfFoo, Decl(privateNameInInExpression.ts, 109, 26))
|
||||
|
||||
class Bar { notFoo = true }
|
||||
>Bar : Symbol(Bar, Decl(privateNameInInExpression.ts, 109, 48))
|
||||
>notFoo : Symbol(Bar.notFoo, Decl(privateNameInInExpression.ts, 110, 11))
|
||||
|
||||
function badSyntax(v: Foo) {
|
||||
>badSyntax : Symbol(badSyntax, Decl(privateNameInInExpression.ts, 110, 27))
|
||||
>v : Symbol(v, Decl(privateNameInInExpression.ts, 112, 19))
|
||||
>Foo : Symbol(Foo, Decl(privateNameInInExpression.ts, 0, 0))
|
||||
|
||||
return #field in v; // Bad - outside of class
|
||||
>v : Symbol(v, Decl(privateNameInInExpression.ts, 112, 19))
|
||||
}
|
||||
|
308
tests/baselines/reference/privateNameInInExpression.types
Normal file
308
tests/baselines/reference/privateNameInInExpression.types
Normal file
|
@ -0,0 +1,308 @@
|
|||
=== 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
|
||||
>#field : any
|
||||
>v : any
|
||||
|
||||
const b = #field in v.p1.p2;
|
||||
>b : boolean
|
||||
>#field in v.p1.p2 : boolean
|
||||
>#field : any
|
||||
>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
|
||||
>#field : any
|
||||
>(v as {}) : {}
|
||||
>v as {} : {}
|
||||
>v : any
|
||||
|
||||
const d = #field in (v as Foo);
|
||||
>d : boolean
|
||||
>#field in (v as Foo) : boolean
|
||||
>#field : any
|
||||
>(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
|
||||
>#field : any
|
||||
>(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
|
||||
>#field : any
|
||||
>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
|
||||
>#field : any
|
||||
>(v as unknown) : unknown
|
||||
>v as unknown : unknown
|
||||
>v : any
|
||||
|
||||
const b = #fiel in v; // Bad - typo in privateID
|
||||
>b : boolean
|
||||
>#fiel in v : boolean
|
||||
>#fiel : 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
|
||||
>v : any
|
||||
|
||||
for (#field in v) { /**/ } // Bad - 'in' not allowed
|
||||
>v : any
|
||||
|
||||
for (let d in #field in v) { /**/ } // Bad - rhs of in should be a object/any
|
||||
>d : string
|
||||
>#field in v : boolean
|
||||
>#field : any
|
||||
>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
|
||||
>#field : any
|
||||
|
||||
/*2*/in/*3*/
|
||||
/*4*/v/*5*/
|
||||
>v : any
|
||||
}
|
||||
flow(u: unknown, n: never, fb: Foo | Bar, fs: FooSub, b: Bar, fsb: FooSub | Bar, fsfb: Foo | FooSub | Bar) {
|
||||
>flow : (u: unknown, n: never, fb: Foo | Bar, fs: FooSub, b: Bar, fsb: FooSub | Bar, fsfb: Foo | FooSub | Bar) => void
|
||||
>u : unknown
|
||||
>n : never
|
||||
>fb : Foo | Bar
|
||||
>fs : FooSub
|
||||
>b : Bar
|
||||
>fsb : Bar | FooSub
|
||||
>fsfb : Foo | 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
|
||||
>#field : any
|
||||
>n : never
|
||||
|
||||
n; // good n is never
|
||||
>n : never
|
||||
}
|
||||
|
||||
if (#field in u) {
|
||||
>#field in u : boolean
|
||||
>#field : any
|
||||
>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
|
||||
>#field : any
|
||||
>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
|
||||
>#method : any
|
||||
>u : object
|
||||
|
||||
u; // good u is Foo
|
||||
>u : Foo
|
||||
}
|
||||
|
||||
if (#staticField in u) {
|
||||
>#staticField in u : boolean
|
||||
>#staticField : any
|
||||
>u : object
|
||||
|
||||
u; // good u is typeof Foo
|
||||
>u : typeof Foo
|
||||
}
|
||||
|
||||
if (#staticMethod in u) {
|
||||
>#staticMethod in u : boolean
|
||||
>#staticMethod : any
|
||||
>u : object
|
||||
|
||||
u; // good u is typeof Foo
|
||||
>u : typeof Foo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (#field in fb) {
|
||||
>#field in fb : boolean
|
||||
>#field : any
|
||||
>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
|
||||
>#field : any
|
||||
>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
|
||||
>#field : any
|
||||
>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
|
||||
>#field : any
|
||||
>fsb : Bar | FooSub
|
||||
|
||||
fsb; // good fsb is FooSub
|
||||
>fsb : FooSub
|
||||
|
||||
} else {
|
||||
fsb; // good fsb is Bar
|
||||
>fsb : Bar
|
||||
}
|
||||
|
||||
if (#field in fsfb) {
|
||||
>#field in fsfb : boolean
|
||||
>#field : any
|
||||
>fsfb : Foo | Bar | FooSub
|
||||
|
||||
fsfb; // good fsfb is 'Foo | FooSub'
|
||||
>fsfb : Foo | FooSub
|
||||
|
||||
} else {
|
||||
fsfb; // good fsfb is Bar
|
||||
>fsfb : Bar
|
||||
}
|
||||
|
||||
class Nested {
|
||||
>Nested : Nested
|
||||
|
||||
m(v: any) {
|
||||
>m : (v: any) => void
|
||||
>v : any
|
||||
|
||||
if (#field in v) {
|
||||
>#field in v : boolean
|
||||
>#field : any
|
||||
>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) => boolean
|
||||
>v : Foo
|
||||
|
||||
return #field in v; // Bad - outside of class
|
||||
>#field in v : boolean
|
||||
>#field : any
|
||||
>v : Foo
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
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(24,14): error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
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 (4 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 'instances' WeakSet
|
||||
#staticField in v; // expect Foo's constructor
|
||||
#staticMethod in v; // expect Foo's constructor
|
||||
}
|
||||
precedence(v: any) {
|
||||
// '==' and '||' have lower precedence than 'in'
|
||||
// 'in' naturally has same precedence as '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 (SyntaxError): (v << #field) in (v << v)
|
||||
~~~~~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
|
||||
v << #field in v == v; // Good precedence (SyntaxError): ((v << #field) in v) == v
|
||||
|
||||
v == #field in v in v; // Good precedence: v == ((#field in v) in v)
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
|
||||
#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
|
||||
}
|
||||
|
||||
export { }
|
||||
|
|
@ -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 'instances' WeakSet
|
||||
#staticField in v; // expect Foo's constructor
|
||||
#staticMethod in v; // expect Foo's constructor
|
||||
}
|
||||
precedence(v: any) {
|
||||
// '==' and '||' have lower precedence than 'in'
|
||||
// 'in' naturally has same precedence as '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 (SyntaxError): (v << #field) in (v << v)
|
||||
|
||||
v << #field in v == v; // Good precedence (SyntaxError): ((v << #field) in v) == v
|
||||
|
||||
v == #field in v in v; // Good precedence: v == ((#field in v) in 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(state, receiver) {
|
||||
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(_Foo_field, v); // expect Foo's 'field' WeakMap
|
||||
__classPrivateFieldIn(_Foo_instances, v); // expect Foo's 'instances' WeakSet
|
||||
__classPrivateFieldIn(_a, v); // expect Foo's constructor
|
||||
__classPrivateFieldIn(_a, v); // expect Foo's constructor
|
||||
}
|
||||
precedence(v) {
|
||||
// '==' and '||' have lower precedence than 'in'
|
||||
// 'in' naturally has same precedence as 'in'
|
||||
// '<<' has higher precedence than 'in'
|
||||
v == __classPrivateFieldIn(_Foo_field, v) || v; // Good precedence: (v == (#field in v)) || v
|
||||
v << in v << v; // Good precedence (SyntaxError): (v << #field) in (v << v)
|
||||
v << in v == v; // Good precedence (SyntaxError): ((v << #field) in v) == v
|
||||
v == __classPrivateFieldIn(_Foo_field, v) in v; // Good precedence: v == ((#field in v) in v)
|
||||
__classPrivateFieldIn(_Foo_field, v) && __classPrivateFieldIn(_Foo_field, v); // Good precedence: (#field in v) && (#field in v)
|
||||
}
|
||||
invalidLHS(v) {
|
||||
'prop' in v;
|
||||
10;
|
||||
__classPrivateFieldIn(_Foo_field, v);
|
||||
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(_Bar_field, v); // 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 {};
|
|
@ -0,0 +1,112 @@
|
|||
=== 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
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpressionTransform.ts, 0, 11))
|
||||
>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 6, 10))
|
||||
|
||||
#method in v; // expect Foo's 'instances' WeakSet
|
||||
>#method : Symbol(Foo.#method, Decl(privateNameInInExpressionTransform.ts, 1, 15))
|
||||
>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 6, 10))
|
||||
|
||||
#staticField in v; // expect Foo's constructor
|
||||
>#staticField : Symbol(Foo.#staticField, Decl(privateNameInInExpressionTransform.ts, 2, 16))
|
||||
>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 6, 10))
|
||||
|
||||
#staticMethod in v; // expect Foo's constructor
|
||||
>#staticMethod : Symbol(Foo.#staticMethod, Decl(privateNameInInExpressionTransform.ts, 3, 27))
|
||||
>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))
|
||||
|
||||
// '==' and '||' have lower precedence than 'in'
|
||||
// 'in' naturally has same precedence as '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))
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpressionTransform.ts, 0, 11))
|
||||
>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 12, 15))
|
||||
>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 12, 15))
|
||||
|
||||
v << #field in v << v; // Good precedence (SyntaxError): (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 (SyntaxError): ((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 in v; // Good precedence: v == ((#field in v) in v)
|
||||
>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 12, 15))
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpressionTransform.ts, 0, 11))
|
||||
>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)
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpressionTransform.ts, 0, 11))
|
||||
>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 12, 15))
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpressionTransform.ts, 0, 11))
|
||||
>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;
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpressionTransform.ts, 0, 11))
|
||||
>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
|
||||
>#field : Symbol(Bar.#field, Decl(privateNameInInExpressionTransform.ts, 33, 11))
|
||||
>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 { }
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
=== 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
|
||||
>#field : any
|
||||
>v : any
|
||||
|
||||
#method in v; // expect Foo's 'instances' WeakSet
|
||||
>#method in v : boolean
|
||||
>#method : any
|
||||
>v : any
|
||||
|
||||
#staticField in v; // expect Foo's constructor
|
||||
>#staticField in v : boolean
|
||||
>#staticField : any
|
||||
>v : any
|
||||
|
||||
#staticMethod in v; // expect Foo's constructor
|
||||
>#staticMethod in v : boolean
|
||||
>#staticMethod : any
|
||||
>v : any
|
||||
}
|
||||
precedence(v: any) {
|
||||
>precedence : (v: any) => void
|
||||
>v : any
|
||||
|
||||
// '==' and '||' have lower precedence than 'in'
|
||||
// 'in' naturally has same precedence as 'in'
|
||||
// '<<' has higher precedence than 'in'
|
||||
|
||||
v == #field in v || v; // Good precedence: (v == (#field in v)) || v
|
||||
>v == #field in v || v : any
|
||||
>v == #field in v : boolean
|
||||
>v : any
|
||||
>#field in v : boolean
|
||||
>#field : any
|
||||
>v : any
|
||||
>v : any
|
||||
|
||||
v << #field in v << v; // Good precedence (SyntaxError): (v << #field) in (v << v)
|
||||
>v << #field in v << v : boolean
|
||||
>v << #field : number
|
||||
>v : any
|
||||
>v << v : number
|
||||
>v : any
|
||||
>v : any
|
||||
|
||||
v << #field in v == v; // Good precedence (SyntaxError): ((v << #field) in v) == v
|
||||
>v << #field in v == v : boolean
|
||||
>v << #field in v : boolean
|
||||
>v << #field : number
|
||||
>v : any
|
||||
>v : any
|
||||
>v : any
|
||||
|
||||
v == #field in v in v; // Good precedence: v == ((#field in v) in v)
|
||||
>v == #field in v in v : boolean
|
||||
>v : any
|
||||
>#field in v in v : boolean
|
||||
>#field in v : boolean
|
||||
>#field : any
|
||||
>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
|
||||
>#field : any
|
||||
>v : any
|
||||
>#field in v : boolean
|
||||
>#field : any
|
||||
>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
|
||||
>#field : any
|
||||
>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
|
||||
>#field : any
|
||||
>v : any
|
||||
}
|
||||
}
|
||||
|
||||
function syntaxError(v: Foo) {
|
||||
>syntaxError : (v: Foo) => boolean
|
||||
>v : Foo
|
||||
|
||||
return #field in v; // expect `return in v` so runtime will have a syntax error
|
||||
>#field in v : boolean
|
||||
>#field : any
|
||||
>v : Foo
|
||||
}
|
||||
|
||||
export { }
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts(4,26): error TS2805: Static fields with private names can't have initializers when the '--useDefineForClassFields' flag is not specified with a '--target' of 'esnext'. Consider adding the '--useDefineForClassFields' flag.
|
||||
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(24,14): error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
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 (5 errors) ====
|
||||
class Foo {
|
||||
#field = 1;
|
||||
#method() {}
|
||||
static #staticField= 2;
|
||||
~
|
||||
!!! error TS2805: Static fields with private names can't have initializers when the '--useDefineForClassFields' flag is not specified with a '--target' of 'esnext'. Consider adding the '--useDefineForClassFields' flag.
|
||||
static #staticMethod() {}
|
||||
|
||||
check(v: any) {
|
||||
#field in v; // expect Foo's 'field' WeakMap
|
||||
#method in v; // expect Foo's 'instances' WeakSet
|
||||
#staticField in v; // expect Foo's constructor
|
||||
#staticMethod in v; // expect Foo's constructor
|
||||
}
|
||||
precedence(v: any) {
|
||||
// '==' and '||' have lower precedence than 'in'
|
||||
// 'in' naturally has same precedence as '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 (SyntaxError): (v << #field) in (v << v)
|
||||
~~~~~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
|
||||
v << #field in v == v; // Good precedence (SyntaxError): ((v << #field) in v) == v
|
||||
|
||||
v == #field in v in v; // Good precedence: v == ((#field in v) in v)
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
|
||||
#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
|
||||
}
|
||||
|
||||
export { }
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
//// [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 'instances' WeakSet
|
||||
#staticField in v; // expect Foo's constructor
|
||||
#staticMethod in v; // expect Foo's constructor
|
||||
}
|
||||
precedence(v: any) {
|
||||
// '==' and '||' have lower precedence than 'in'
|
||||
// 'in' naturally has same precedence as '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 (SyntaxError): (v << #field) in (v << v)
|
||||
|
||||
v << #field in v == v; // Good precedence (SyntaxError): ((v << #field) in v) == v
|
||||
|
||||
v == #field in v in v; // Good precedence: v == ((#field in v) in 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]
|
||||
class Foo {
|
||||
#field = 1;
|
||||
#method() { }
|
||||
static #staticField = 2;
|
||||
static #staticMethod() { }
|
||||
check(v) {
|
||||
#field in v; // expect Foo's 'field' WeakMap
|
||||
#method in v; // expect Foo's 'instances' WeakSet
|
||||
#staticField in v; // expect Foo's constructor
|
||||
#staticMethod in v; // expect Foo's constructor
|
||||
}
|
||||
precedence(v) {
|
||||
// '==' and '||' have lower precedence than 'in'
|
||||
// 'in' naturally has same precedence as '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 (SyntaxError): (v << #field) in (v << v)
|
||||
v << #field in v == v; // Good precedence (SyntaxError): ((v << #field) in v) == v
|
||||
v == #field in v in v; // Good precedence: v == ((#field in v) in v)
|
||||
#field in v && #field in v; // Good precedence: (#field in v) && (#field in v)
|
||||
}
|
||||
invalidLHS(v) {
|
||||
'prop' in v;
|
||||
10;
|
||||
#field in v;
|
||||
10;
|
||||
}
|
||||
}
|
||||
class Bar {
|
||||
#field = 1;
|
||||
check(v) {
|
||||
#field in v; // expect Bar's 'field' WeakMap
|
||||
}
|
||||
}
|
||||
function syntaxError(v) {
|
||||
return #field in v; // expect `return in v` so runtime will have a syntax error
|
||||
}
|
||||
export {};
|
|
@ -0,0 +1,112 @@
|
|||
=== 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
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpressionTransform.ts, 0, 11))
|
||||
>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 6, 10))
|
||||
|
||||
#method in v; // expect Foo's 'instances' WeakSet
|
||||
>#method : Symbol(Foo.#method, Decl(privateNameInInExpressionTransform.ts, 1, 15))
|
||||
>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 6, 10))
|
||||
|
||||
#staticField in v; // expect Foo's constructor
|
||||
>#staticField : Symbol(Foo.#staticField, Decl(privateNameInInExpressionTransform.ts, 2, 16))
|
||||
>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 6, 10))
|
||||
|
||||
#staticMethod in v; // expect Foo's constructor
|
||||
>#staticMethod : Symbol(Foo.#staticMethod, Decl(privateNameInInExpressionTransform.ts, 3, 27))
|
||||
>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))
|
||||
|
||||
// '==' and '||' have lower precedence than 'in'
|
||||
// 'in' naturally has same precedence as '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))
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpressionTransform.ts, 0, 11))
|
||||
>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 12, 15))
|
||||
>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 12, 15))
|
||||
|
||||
v << #field in v << v; // Good precedence (SyntaxError): (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 (SyntaxError): ((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 in v; // Good precedence: v == ((#field in v) in v)
|
||||
>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 12, 15))
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpressionTransform.ts, 0, 11))
|
||||
>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)
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpressionTransform.ts, 0, 11))
|
||||
>v : Symbol(v, Decl(privateNameInInExpressionTransform.ts, 12, 15))
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpressionTransform.ts, 0, 11))
|
||||
>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;
|
||||
>#field : Symbol(Foo.#field, Decl(privateNameInInExpressionTransform.ts, 0, 11))
|
||||
>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
|
||||
>#field : Symbol(Bar.#field, Decl(privateNameInInExpressionTransform.ts, 33, 11))
|
||||
>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 { }
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
=== 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
|
||||
>#field : any
|
||||
>v : any
|
||||
|
||||
#method in v; // expect Foo's 'instances' WeakSet
|
||||
>#method in v : boolean
|
||||
>#method : any
|
||||
>v : any
|
||||
|
||||
#staticField in v; // expect Foo's constructor
|
||||
>#staticField in v : boolean
|
||||
>#staticField : any
|
||||
>v : any
|
||||
|
||||
#staticMethod in v; // expect Foo's constructor
|
||||
>#staticMethod in v : boolean
|
||||
>#staticMethod : any
|
||||
>v : any
|
||||
}
|
||||
precedence(v: any) {
|
||||
>precedence : (v: any) => void
|
||||
>v : any
|
||||
|
||||
// '==' and '||' have lower precedence than 'in'
|
||||
// 'in' naturally has same precedence as 'in'
|
||||
// '<<' has higher precedence than 'in'
|
||||
|
||||
v == #field in v || v; // Good precedence: (v == (#field in v)) || v
|
||||
>v == #field in v || v : any
|
||||
>v == #field in v : boolean
|
||||
>v : any
|
||||
>#field in v : boolean
|
||||
>#field : any
|
||||
>v : any
|
||||
>v : any
|
||||
|
||||
v << #field in v << v; // Good precedence (SyntaxError): (v << #field) in (v << v)
|
||||
>v << #field in v << v : boolean
|
||||
>v << #field : number
|
||||
>v : any
|
||||
>v << v : number
|
||||
>v : any
|
||||
>v : any
|
||||
|
||||
v << #field in v == v; // Good precedence (SyntaxError): ((v << #field) in v) == v
|
||||
>v << #field in v == v : boolean
|
||||
>v << #field in v : boolean
|
||||
>v << #field : number
|
||||
>v : any
|
||||
>v : any
|
||||
>v : any
|
||||
|
||||
v == #field in v in v; // Good precedence: v == ((#field in v) in v)
|
||||
>v == #field in v in v : boolean
|
||||
>v : any
|
||||
>#field in v in v : boolean
|
||||
>#field in v : boolean
|
||||
>#field : any
|
||||
>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
|
||||
>#field : any
|
||||
>v : any
|
||||
>#field in v : boolean
|
||||
>#field : any
|
||||
>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
|
||||
>#field : any
|
||||
>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
|
||||
>#field : any
|
||||
>v : any
|
||||
}
|
||||
}
|
||||
|
||||
function syntaxError(v: Foo) {
|
||||
>syntaxError : (v: Foo) => boolean
|
||||
>v : Foo
|
||||
|
||||
return #field in v; // expect `return in v` so runtime will have a syntax error
|
||||
>#field in v : boolean
|
||||
>#field : any
|
||||
>v : Foo
|
||||
}
|
||||
|
||||
export { }
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
22
tests/baselines/reference/privateNameInInExpressionUnused.js
Normal file
22
tests/baselines/reference/privateNameInInExpressionUnused.js
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
=== 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;
|
||||
>#brand : Symbol(Foo.#brand, Decl(privateNameInInExpressionUnused.ts, 1, 23))
|
||||
>v : Symbol(v, Decl(privateNameInInExpressionUnused.ts, 4, 10))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
=== 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
|
||||
>#brand : any
|
||||
>v : any
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ declare var dec: any;
|
|||
@dec export class A {
|
||||
#x: number = 1;
|
||||
async f() { this.#x = await this.#x; }
|
||||
g(u) { return #x in u; }
|
||||
}
|
||||
|
||||
const o = { a: 1 };
|
||||
|
@ -19,3 +20,4 @@ export declare function __metadata(metadataKey: any, metadataValue: any): Functi
|
|||
export declare function __awaiter(thisArg: any, _arguments: any, P: Function, generator: Function): any;
|
||||
export declare function __classPrivateFieldGet(a: any, b: any, c: any, d: any): any;
|
||||
export declare function __classPrivateFieldSet(a: any, b: any, c: any, d: any, e: any): any;
|
||||
export declare function __classPrivateFieldIn(a: any, b: any): boolean;
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
// @importHelpers: true
|
||||
// @target: es2020
|
||||
// @module: commonjs
|
||||
// @lib: esnext
|
||||
// @moduleResolution: classic
|
||||
// @filename: main.ts
|
||||
export class Foo {
|
||||
#field = true;
|
||||
f() {
|
||||
this.#field = this.#field;
|
||||
#field in this;
|
||||
}
|
||||
}
|
||||
|
||||
// @filename: tslib.d.ts
|
||||
export {}
|
|
@ -0,0 +1,119 @@
|
|||
// @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, fsfb: Foo | 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
|
||||
}
|
||||
|
||||
if (#field in fsfb) {
|
||||
fsfb; // good fsfb is 'Foo | FooSub'
|
||||
} else {
|
||||
fsfb; // good fsfb 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
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
// @target: esnext, 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 'instances' WeakSet
|
||||
#staticField in v; // expect Foo's constructor
|
||||
#staticMethod in v; // expect Foo's constructor
|
||||
}
|
||||
precedence(v: any) {
|
||||
// '==' and '||' have lower precedence than 'in'
|
||||
// 'in' naturally has same precedence as '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 (SyntaxError): (v << #field) in (v << v)
|
||||
|
||||
v << #field in v == v; // Good precedence (SyntaxError): ((v << #field) in v) == v
|
||||
|
||||
v == #field in v in v; // Good precedence: v == ((#field in v) in 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 { }
|
|
@ -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;
|
||||
}
|
||||
}
|
19
tests/cases/fourslash/codeFixSpellingPrivateNameInIn.ts
Normal file
19
tests/cases/fourslash/codeFixSpellingPrivateNameInIn.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////class A {
|
||||
//// #foo: number;
|
||||
//// static isA(v: A) {
|
||||
//// [|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;"
|
||||
});
|
|
@ -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]);
|
||||
|
|
Loading…
Reference in a new issue