Fix #33569 - Enable declaration emit for late-bound function members (#53034)

This commit is contained in:
Wesley Wigham
2023-03-15 10:20:35 -07:00
committed by GitHub
parent 9ccf47fec5
commit 2b9d792828
12 changed files with 427 additions and 7 deletions
+8 -1
View File
@@ -5105,6 +5105,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (name === InternalSymbolName.ExportEquals) return;
merged.exports!.set(name, merged.exports!.has(name) ? mergeSymbol(merged.exports!.get(name)!, s) : s);
});
if (merged === exported) {
// We just mutated a symbol, reset any cached links we may have already set
// (Notably required to make late bound members appear)
getSymbolLinks(merged).resolvedExports = undefined;
getSymbolLinks(merged).resolvedMembers = undefined;
}
getSymbolLinks(merged).cjsExportMerged = merged;
return links.cjsExportMerged = merged;
}
@@ -8887,7 +8893,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
function getNamespaceMembersForSerialization(symbol: Symbol) {
return !symbol.exports ? [] : filter(arrayFrom(symbol.exports.values()), isNamespaceMember);
const exports = getExportsOfSymbol(symbol);
return !exports ? [] : filter(arrayFrom(exports.values()), m => isNamespaceMember(m) && isIdentifierText(m.escapedName as string, ScriptTarget.ESNext));
}
function isTypeOnlyNamespace(symbol: Symbol) {
+10 -3
View File
@@ -94,11 +94,13 @@ import {
isAnyImportSyntax,
isArray,
isArrayBindingElement,
isBinaryExpression,
isBindingElement,
isBindingPattern,
isClassDeclaration,
isClassElement,
isDeclaration,
isElementAccessExpression,
isEntityName,
isEntityNameExpression,
isExportAssignment,
@@ -114,6 +116,7 @@ import {
isGlobalScopeAugmentation,
isIdentifier,
isIdentifierANonContextualKeyword,
isIdentifierText,
isImportDeclaration,
isImportEqualsDeclaration,
isIndexSignatureDeclaration,
@@ -181,6 +184,7 @@ import {
pushIfUnique,
removeAllComments,
ResolutionMode,
ScriptTarget,
SetAccessorDeclaration,
setCommentRange,
setEmitFlags,
@@ -1490,13 +1494,16 @@ export function transformDeclarations(context: TransformationContext) {
fakespace.symbol = props[0].parent!;
const exportMappings: [Identifier, string][] = [];
let declarations: (VariableStatement | ExportDeclaration)[] = mapDefined(props, p => {
if (!p.valueDeclaration || !isPropertyAccessExpression(p.valueDeclaration)) {
return undefined; // TODO GH#33569: Handle element access expressions that created late bound names (rather than silently omitting them)
if (!p.valueDeclaration || !(isPropertyAccessExpression(p.valueDeclaration) || isElementAccessExpression(p.valueDeclaration) || isBinaryExpression(p.valueDeclaration))) {
return undefined;
}
const nameStr = unescapeLeadingUnderscores(p.escapedName);
if (!isIdentifierText(nameStr, ScriptTarget.ESNext)) {
return undefined; // unique symbol or non-identifier name - omit, since there's no syntax that can preserve it
}
getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(p.valueDeclaration);
const type = resolver.createTypeOfDeclaration(p.valueDeclaration, fakespace, declarationEmitNodeBuilderFlags, symbolTracker);
getSymbolAccessibilityDiagnostic = oldDiag;
const nameStr = unescapeLeadingUnderscores(p.escapedName);
const isNonContextualKeywordName = isStringANonContextualKeyword(nameStr);
const name = isNonContextualKeywordName ? factory.getGeneratedNameForNode(p.valueDeclaration) : factory.createIdentifier(nameStr);
if (isNonContextualKeywordName) {
@@ -1,4 +1,5 @@
import {
BinaryExpression,
BindingElement,
CallSignatureDeclaration,
ConstructorDeclaration,
@@ -8,6 +9,7 @@ import {
DeclarationName,
DiagnosticMessage,
Diagnostics,
ElementAccessExpression,
ExpressionWithTypeArguments,
FunctionDeclaration,
GetAccessorDeclaration,
@@ -15,11 +17,13 @@ import {
hasSyntacticModifier,
ImportEqualsDeclaration,
IndexSignatureDeclaration,
isBinaryExpression,
isBindingElement,
isCallSignatureDeclaration,
isClassDeclaration,
isConstructorDeclaration,
isConstructSignatureDeclaration,
isElementAccessExpression,
isExpressionWithTypeArguments,
isFunctionDeclaration,
isGetAccessor,
@@ -92,6 +96,8 @@ export type DeclarationDiagnosticProducing =
| ConstructorDeclaration
| IndexSignatureDeclaration
| PropertyAccessExpression
| ElementAccessExpression
| BinaryExpression
| JSDocTypedefTag
| JSDocCallbackTag
| JSDocEnumTag;
@@ -117,6 +123,8 @@ export function canProduceDiagnostics(node: Node): node is DeclarationDiagnostic
isConstructorDeclaration(node) ||
isIndexSignatureDeclaration(node) ||
isPropertyAccessExpression(node) ||
isElementAccessExpression(node) ||
isBinaryExpression(node) ||
isJSDocTypeAlias(node);
}
@@ -196,7 +204,7 @@ export function createGetSymbolAccessibilityDiagnosticForNodeName(node: Declarat
/** @internal */
export function createGetSymbolAccessibilityDiagnosticForNode(node: DeclarationDiagnosticProducing): GetSymbolAccessibilityDiagnostic {
if (isVariableDeclaration(node) || isPropertyDeclaration(node) || isPropertySignature(node) || isPropertyAccessExpression(node) || isBindingElement(node) || isConstructorDeclaration(node)) {
if (isVariableDeclaration(node) || isPropertyDeclaration(node) || isPropertySignature(node) || isPropertyAccessExpression(node) || isElementAccessExpression(node) || isBinaryExpression(node) || isBindingElement(node) || isConstructorDeclaration(node)) {
return getVariableDeclarationTypeVisibilityError;
}
else if (isSetAccessor(node) || isGetAccessor(node)) {
@@ -237,7 +245,7 @@ export function createGetSymbolAccessibilityDiagnosticForNode(node: DeclarationD
}
// This check is to ensure we don't report error on constructor parameter property as that error would be reported during parameter emit
// The only exception here is if the constructor was marked as private. we are not emitting the constructor parameters at all.
else if (node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertyAccessExpression || node.kind === SyntaxKind.PropertySignature ||
else if (node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertyAccessExpression || node.kind === SyntaxKind.ElementAccessExpression || node.kind === SyntaxKind.BinaryExpression || node.kind === SyntaxKind.PropertySignature ||
(node.kind === SyntaxKind.Parameter && hasSyntacticModifier(node.parent, ModifierFlags.Private))) {
// TODO(jfreeman): Deal with computed properties in error reporting.
if (isStatic(node)) {
+1 -1
View File
@@ -5659,7 +5659,7 @@ export interface EmitResolver {
isOptionalUninitializedParameterProperty(node: ParameterDeclaration): boolean;
isExpandoFunctionDeclaration(node: FunctionDeclaration): boolean;
getPropertiesOfContainerFunction(node: Declaration): Symbol[];
createTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean): TypeNode | undefined;
createTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression | ElementAccessExpression | BinaryExpression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean): TypeNode | undefined;
createReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined;
createTypeOfExpression(expr: Expression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined;
createLiteralConstValue(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration, tracker: SymbolTracker): Expression;
@@ -0,0 +1,40 @@
//// [declarationEmitLateBoundAssignments.ts]
export function foo() {}
foo.bar = 12;
const _private = Symbol();
foo[_private] = "ok";
const strMem = "strMemName";
foo[strMem] = "ok";
const dashStrMem = "dashed-str-mem";
foo[dashStrMem] = "ok";
const numMem = 42;
foo[numMem] = "ok";
const x: string = foo[_private];
const y: string = foo[strMem];
const z: string = foo[numMem];
const a: string = foo[dashStrMem];
//// [declarationEmitLateBoundAssignments.js]
export function foo() { }
foo.bar = 12;
const _private = Symbol();
foo[_private] = "ok";
const strMem = "strMemName";
foo[strMem] = "ok";
const dashStrMem = "dashed-str-mem";
foo[dashStrMem] = "ok";
const numMem = 42;
foo[numMem] = "ok";
const x = foo[_private];
const y = foo[strMem];
const z = foo[numMem];
const a = foo[dashStrMem];
//// [declarationEmitLateBoundAssignments.d.ts]
export declare function foo(): void;
export declare namespace foo {
var bar: number;
var strMemName: string;
}
@@ -0,0 +1,58 @@
=== tests/cases/compiler/declarationEmitLateBoundAssignments.ts ===
export function foo() {}
>foo : Symbol(foo, Decl(declarationEmitLateBoundAssignments.ts, 0, 0), Decl(declarationEmitLateBoundAssignments.ts, 0, 24), Decl(declarationEmitLateBoundAssignments.ts, 2, 26), Decl(declarationEmitLateBoundAssignments.ts, 4, 28), Decl(declarationEmitLateBoundAssignments.ts, 6, 36) ... and 1 more)
foo.bar = 12;
>foo.bar : Symbol(foo.bar, Decl(declarationEmitLateBoundAssignments.ts, 0, 24))
>foo : Symbol(foo, Decl(declarationEmitLateBoundAssignments.ts, 0, 0), Decl(declarationEmitLateBoundAssignments.ts, 0, 24), Decl(declarationEmitLateBoundAssignments.ts, 2, 26), Decl(declarationEmitLateBoundAssignments.ts, 4, 28), Decl(declarationEmitLateBoundAssignments.ts, 6, 36) ... and 1 more)
>bar : Symbol(foo.bar, Decl(declarationEmitLateBoundAssignments.ts, 0, 24))
const _private = Symbol();
>_private : Symbol(_private, Decl(declarationEmitLateBoundAssignments.ts, 2, 5))
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
foo[_private] = "ok";
>foo : Symbol(foo, Decl(declarationEmitLateBoundAssignments.ts, 0, 0), Decl(declarationEmitLateBoundAssignments.ts, 0, 24), Decl(declarationEmitLateBoundAssignments.ts, 2, 26), Decl(declarationEmitLateBoundAssignments.ts, 4, 28), Decl(declarationEmitLateBoundAssignments.ts, 6, 36) ... and 1 more)
>_private : Symbol(_private, Decl(declarationEmitLateBoundAssignments.ts, 2, 5))
const strMem = "strMemName";
>strMem : Symbol(strMem, Decl(declarationEmitLateBoundAssignments.ts, 4, 5))
foo[strMem] = "ok";
>foo : Symbol(foo, Decl(declarationEmitLateBoundAssignments.ts, 0, 0), Decl(declarationEmitLateBoundAssignments.ts, 0, 24), Decl(declarationEmitLateBoundAssignments.ts, 2, 26), Decl(declarationEmitLateBoundAssignments.ts, 4, 28), Decl(declarationEmitLateBoundAssignments.ts, 6, 36) ... and 1 more)
>strMem : Symbol(strMem, Decl(declarationEmitLateBoundAssignments.ts, 4, 5))
const dashStrMem = "dashed-str-mem";
>dashStrMem : Symbol(dashStrMem, Decl(declarationEmitLateBoundAssignments.ts, 6, 5))
foo[dashStrMem] = "ok";
>foo : Symbol(foo, Decl(declarationEmitLateBoundAssignments.ts, 0, 0), Decl(declarationEmitLateBoundAssignments.ts, 0, 24), Decl(declarationEmitLateBoundAssignments.ts, 2, 26), Decl(declarationEmitLateBoundAssignments.ts, 4, 28), Decl(declarationEmitLateBoundAssignments.ts, 6, 36) ... and 1 more)
>dashStrMem : Symbol(dashStrMem, Decl(declarationEmitLateBoundAssignments.ts, 6, 5))
const numMem = 42;
>numMem : Symbol(numMem, Decl(declarationEmitLateBoundAssignments.ts, 8, 5))
foo[numMem] = "ok";
>foo : Symbol(foo, Decl(declarationEmitLateBoundAssignments.ts, 0, 0), Decl(declarationEmitLateBoundAssignments.ts, 0, 24), Decl(declarationEmitLateBoundAssignments.ts, 2, 26), Decl(declarationEmitLateBoundAssignments.ts, 4, 28), Decl(declarationEmitLateBoundAssignments.ts, 6, 36) ... and 1 more)
>numMem : Symbol(numMem, Decl(declarationEmitLateBoundAssignments.ts, 8, 5))
const x: string = foo[_private];
>x : Symbol(x, Decl(declarationEmitLateBoundAssignments.ts, 11, 5))
>foo : Symbol(foo, Decl(declarationEmitLateBoundAssignments.ts, 0, 0), Decl(declarationEmitLateBoundAssignments.ts, 0, 24), Decl(declarationEmitLateBoundAssignments.ts, 2, 26), Decl(declarationEmitLateBoundAssignments.ts, 4, 28), Decl(declarationEmitLateBoundAssignments.ts, 6, 36) ... and 1 more)
>_private : Symbol(_private, Decl(declarationEmitLateBoundAssignments.ts, 2, 5))
const y: string = foo[strMem];
>y : Symbol(y, Decl(declarationEmitLateBoundAssignments.ts, 12, 5))
>foo : Symbol(foo, Decl(declarationEmitLateBoundAssignments.ts, 0, 0), Decl(declarationEmitLateBoundAssignments.ts, 0, 24), Decl(declarationEmitLateBoundAssignments.ts, 2, 26), Decl(declarationEmitLateBoundAssignments.ts, 4, 28), Decl(declarationEmitLateBoundAssignments.ts, 6, 36) ... and 1 more)
>strMem : Symbol(strMem, Decl(declarationEmitLateBoundAssignments.ts, 4, 5))
const z: string = foo[numMem];
>z : Symbol(z, Decl(declarationEmitLateBoundAssignments.ts, 13, 5))
>foo : Symbol(foo, Decl(declarationEmitLateBoundAssignments.ts, 0, 0), Decl(declarationEmitLateBoundAssignments.ts, 0, 24), Decl(declarationEmitLateBoundAssignments.ts, 2, 26), Decl(declarationEmitLateBoundAssignments.ts, 4, 28), Decl(declarationEmitLateBoundAssignments.ts, 6, 36) ... and 1 more)
>numMem : Symbol(numMem, Decl(declarationEmitLateBoundAssignments.ts, 8, 5))
const a: string = foo[dashStrMem];
>a : Symbol(a, Decl(declarationEmitLateBoundAssignments.ts, 14, 5))
>foo : Symbol(foo, Decl(declarationEmitLateBoundAssignments.ts, 0, 0), Decl(declarationEmitLateBoundAssignments.ts, 0, 24), Decl(declarationEmitLateBoundAssignments.ts, 2, 26), Decl(declarationEmitLateBoundAssignments.ts, 4, 28), Decl(declarationEmitLateBoundAssignments.ts, 6, 36) ... and 1 more)
>dashStrMem : Symbol(dashStrMem, Decl(declarationEmitLateBoundAssignments.ts, 6, 5))
@@ -0,0 +1,80 @@
=== tests/cases/compiler/declarationEmitLateBoundAssignments.ts ===
export function foo() {}
>foo : typeof foo
foo.bar = 12;
>foo.bar = 12 : 12
>foo.bar : number
>foo : typeof foo
>bar : number
>12 : 12
const _private = Symbol();
>_private : unique symbol
>Symbol() : unique symbol
>Symbol : SymbolConstructor
foo[_private] = "ok";
>foo[_private] = "ok" : "ok"
>foo[_private] : string
>foo : typeof foo
>_private : unique symbol
>"ok" : "ok"
const strMem = "strMemName";
>strMem : "strMemName"
>"strMemName" : "strMemName"
foo[strMem] = "ok";
>foo[strMem] = "ok" : "ok"
>foo[strMem] : string
>foo : typeof foo
>strMem : "strMemName"
>"ok" : "ok"
const dashStrMem = "dashed-str-mem";
>dashStrMem : "dashed-str-mem"
>"dashed-str-mem" : "dashed-str-mem"
foo[dashStrMem] = "ok";
>foo[dashStrMem] = "ok" : "ok"
>foo[dashStrMem] : string
>foo : typeof foo
>dashStrMem : "dashed-str-mem"
>"ok" : "ok"
const numMem = 42;
>numMem : 42
>42 : 42
foo[numMem] = "ok";
>foo[numMem] = "ok" : "ok"
>foo[numMem] : string
>foo : typeof foo
>numMem : 42
>"ok" : "ok"
const x: string = foo[_private];
>x : string
>foo[_private] : string
>foo : typeof foo
>_private : unique symbol
const y: string = foo[strMem];
>y : string
>foo[strMem] : string
>foo : typeof foo
>strMem : "strMemName"
const z: string = foo[numMem];
>z : string
>foo[numMem] : string
>foo : typeof foo
>numMem : 42
const a: string = foo[dashStrMem];
>a : string
>foo[dashStrMem] : string
>foo : typeof foo
>dashStrMem : "dashed-str-mem"
@@ -0,0 +1,30 @@
//// [file.js]
export function foo() {}
foo.bar = 12;
const _private = Symbol();
foo[_private] = "ok";
const strMem = "strMemName";
foo[strMem] = "ok";
const dashStrMem = "dashed-str-mem";
foo[dashStrMem] = "ok";
const numMem = 42;
foo[numMem] = "ok";
/** @type {string} */
const x = foo[_private];
/** @type {string} */
const y = foo[strMem];
/** @type {string} */
const z = foo[numMem];
/** @type {string} */
const a = foo[dashStrMem];
//// [file.d.ts]
export function foo(): void;
export namespace foo {
const bar: number;
const strMemName: string;
}
@@ -0,0 +1,62 @@
=== tests/cases/compiler/file.js ===
export function foo() {}
>foo : Symbol(foo, Decl(file.js, 0, 0), Decl(file.js, 0, 24), Decl(file.js, 2, 26), Decl(file.js, 4, 28), Decl(file.js, 6, 36) ... and 1 more)
foo.bar = 12;
>foo.bar : Symbol(foo.bar, Decl(file.js, 0, 24))
>foo : Symbol(foo, Decl(file.js, 0, 0), Decl(file.js, 0, 24), Decl(file.js, 2, 26), Decl(file.js, 4, 28), Decl(file.js, 6, 36) ... and 1 more)
>bar : Symbol(foo.bar, Decl(file.js, 0, 24))
const _private = Symbol();
>_private : Symbol(_private, Decl(file.js, 2, 5))
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
foo[_private] = "ok";
>foo : Symbol(foo, Decl(file.js, 0, 0), Decl(file.js, 0, 24), Decl(file.js, 2, 26), Decl(file.js, 4, 28), Decl(file.js, 6, 36) ... and 1 more)
>_private : Symbol(_private, Decl(file.js, 2, 5))
const strMem = "strMemName";
>strMem : Symbol(strMem, Decl(file.js, 4, 5))
foo[strMem] = "ok";
>foo : Symbol(foo, Decl(file.js, 0, 0), Decl(file.js, 0, 24), Decl(file.js, 2, 26), Decl(file.js, 4, 28), Decl(file.js, 6, 36) ... and 1 more)
>strMem : Symbol(strMem, Decl(file.js, 4, 5))
const dashStrMem = "dashed-str-mem";
>dashStrMem : Symbol(dashStrMem, Decl(file.js, 6, 5))
foo[dashStrMem] = "ok";
>foo : Symbol(foo, Decl(file.js, 0, 0), Decl(file.js, 0, 24), Decl(file.js, 2, 26), Decl(file.js, 4, 28), Decl(file.js, 6, 36) ... and 1 more)
>dashStrMem : Symbol(dashStrMem, Decl(file.js, 6, 5))
const numMem = 42;
>numMem : Symbol(numMem, Decl(file.js, 8, 5))
foo[numMem] = "ok";
>foo : Symbol(foo, Decl(file.js, 0, 0), Decl(file.js, 0, 24), Decl(file.js, 2, 26), Decl(file.js, 4, 28), Decl(file.js, 6, 36) ... and 1 more)
>numMem : Symbol(numMem, Decl(file.js, 8, 5))
/** @type {string} */
const x = foo[_private];
>x : Symbol(x, Decl(file.js, 12, 5))
>foo : Symbol(foo, Decl(file.js, 0, 0), Decl(file.js, 0, 24), Decl(file.js, 2, 26), Decl(file.js, 4, 28), Decl(file.js, 6, 36) ... and 1 more)
>_private : Symbol(_private, Decl(file.js, 2, 5))
/** @type {string} */
const y = foo[strMem];
>y : Symbol(y, Decl(file.js, 14, 5))
>foo : Symbol(foo, Decl(file.js, 0, 0), Decl(file.js, 0, 24), Decl(file.js, 2, 26), Decl(file.js, 4, 28), Decl(file.js, 6, 36) ... and 1 more)
>strMem : Symbol(strMem, Decl(file.js, 4, 5))
/** @type {string} */
const z = foo[numMem];
>z : Symbol(z, Decl(file.js, 16, 5))
>foo : Symbol(foo, Decl(file.js, 0, 0), Decl(file.js, 0, 24), Decl(file.js, 2, 26), Decl(file.js, 4, 28), Decl(file.js, 6, 36) ... and 1 more)
>numMem : Symbol(numMem, Decl(file.js, 8, 5))
/** @type {string} */
const a = foo[dashStrMem];
>a : Symbol(a, Decl(file.js, 18, 5))
>foo : Symbol(foo, Decl(file.js, 0, 0), Decl(file.js, 0, 24), Decl(file.js, 2, 26), Decl(file.js, 4, 28), Decl(file.js, 6, 36) ... and 1 more)
>dashStrMem : Symbol(dashStrMem, Decl(file.js, 6, 5))
@@ -0,0 +1,84 @@
=== tests/cases/compiler/file.js ===
export function foo() {}
>foo : typeof foo
foo.bar = 12;
>foo.bar = 12 : 12
>foo.bar : number
>foo : typeof foo
>bar : number
>12 : 12
const _private = Symbol();
>_private : unique symbol
>Symbol() : unique symbol
>Symbol : SymbolConstructor
foo[_private] = "ok";
>foo[_private] = "ok" : "ok"
>foo[_private] : string
>foo : typeof foo
>_private : unique symbol
>"ok" : "ok"
const strMem = "strMemName";
>strMem : "strMemName"
>"strMemName" : "strMemName"
foo[strMem] = "ok";
>foo[strMem] = "ok" : "ok"
>foo[strMem] : string
>foo : typeof foo
>strMem : "strMemName"
>"ok" : "ok"
const dashStrMem = "dashed-str-mem";
>dashStrMem : "dashed-str-mem"
>"dashed-str-mem" : "dashed-str-mem"
foo[dashStrMem] = "ok";
>foo[dashStrMem] = "ok" : "ok"
>foo[dashStrMem] : string
>foo : typeof foo
>dashStrMem : "dashed-str-mem"
>"ok" : "ok"
const numMem = 42;
>numMem : 42
>42 : 42
foo[numMem] = "ok";
>foo[numMem] = "ok" : "ok"
>foo[numMem] : string
>foo : typeof foo
>numMem : 42
>"ok" : "ok"
/** @type {string} */
const x = foo[_private];
>x : string
>foo[_private] : string
>foo : typeof foo
>_private : unique symbol
/** @type {string} */
const y = foo[strMem];
>y : string
>foo[strMem] : string
>foo : typeof foo
>strMem : "strMemName"
/** @type {string} */
const z = foo[numMem];
>z : string
>foo[numMem] : string
>foo : typeof foo
>numMem : 42
/** @type {string} */
const a = foo[dashStrMem];
>a : string
>foo[dashStrMem] : string
>foo : typeof foo
>dashStrMem : "dashed-str-mem"
@@ -0,0 +1,18 @@
// @strict: true
// @declaration: true
// @target: es6
export function foo() {}
foo.bar = 12;
const _private = Symbol();
foo[_private] = "ok";
const strMem = "strMemName";
foo[strMem] = "ok";
const dashStrMem = "dashed-str-mem";
foo[dashStrMem] = "ok";
const numMem = 42;
foo[numMem] = "ok";
const x: string = foo[_private];
const y: string = foo[strMem];
const z: string = foo[numMem];
const a: string = foo[dashStrMem];
@@ -0,0 +1,26 @@
// @strict: true
// @declaration: true
// @target: es6
// @checkJs: true
// @allowJs: true
// @emitDeclarationOnly: true
// @filename: file.js
export function foo() {}
foo.bar = 12;
const _private = Symbol();
foo[_private] = "ok";
const strMem = "strMemName";
foo[strMem] = "ok";
const dashStrMem = "dashed-str-mem";
foo[dashStrMem] = "ok";
const numMem = 42;
foo[numMem] = "ok";
/** @type {string} */
const x = foo[_private];
/** @type {string} */
const y = foo[strMem];
/** @type {string} */
const z = foo[numMem];
/** @type {string} */
const a = foo[dashStrMem];