Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jsdoc property description #50269

Merged
merged 16 commits into from Aug 25, 2022
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/compiler/checker.ts
Expand Up @@ -439,6 +439,7 @@ namespace ts {
getTypeOfPropertyOfType: (type, name) => getTypeOfPropertyOfType(type, escapeLeadingUnderscores(name)),
getIndexInfoOfType: (type, kind) => getIndexInfoOfType(type, kind === IndexKind.String ? stringType : numberType),
getIndexInfosOfType,
getIndexInfosOfIndexSymbol,
getSignaturesOfType,
getIndexTypeOfType: (type, kind) => getIndexTypeOfType(type, kind === IndexKind.String ? stringType : numberType),
getIndexType: type => getIndexType(type),
Expand Down Expand Up @@ -42554,6 +42555,35 @@ namespace ts {

if (name.kind === SyntaxKind.PropertyAccessExpression) {
checkPropertyAccessExpression(name, CheckMode.Normal);
if (!links.resolvedSymbol) {
const expressionType = checkExpressionCached(name.expression);
const infos = getApplicableIndexInfos(expressionType, getLiteralTypeFromPropertyName(name.name));
if (infos.length && (expressionType as any).members && (expressionType as any).members.get(InternalSymbolName.Index)) {
danay1999 marked this conversation as resolved.
Show resolved Hide resolved
const resolved = resolveStructuredTypeMembers(expressionType as ObjectType);
const symbol = resolved.members.get(InternalSymbolName.Index);
if (infos === getIndexInfosOfType(expressionType)) {
links.resolvedSymbol = symbol;
}
else if (symbol) {
const symbolLinks = getSymbolLinks(symbol);
const declarationList = mapDefined(infos, i => i.declaration);
const nodeListId = map(declarationList, getNodeId).join(",");
if (!symbolLinks.filteredIndexSymbolCache) {
symbolLinks.filteredIndexSymbolCache = new Map();
}
if (symbolLinks.filteredIndexSymbolCache.has(nodeListId)) {
links.resolvedSymbol = symbolLinks.filteredIndexSymbolCache.get(nodeListId)!;
}
else {
const copy = createSymbol(SymbolFlags.Signature, InternalSymbolName.Index);
copy.declarations = mapDefined(infos, i => i.declaration);
copy.parent = expressionType.aliasSymbol ? expressionType.aliasSymbol : expressionType.symbol ? expressionType.symbol : getSymbolAtLocation(copy.declarations[0].parent);
symbolLinks.filteredIndexSymbolCache.set(nodeListId, copy);
links.resolvedSymbol = symbolLinks.filteredIndexSymbolCache.get(nodeListId)!;
}
}
}
}
}
danay1999 marked this conversation as resolved.
Show resolved Hide resolved
else {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we creating a new symbol here? Given

interface Foo { [key: string]: any }
declare let foo: Foo;
foo.bar;
foo.bar;
foo.bar;
foo.bar;

every mention of foo.bar would have its own copy of the index symbol, which seems wrong.

Copy link
Member

@weswigham weswigham Aug 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggested it to handle filtering the symbol's declarations to only those matching the use site in order to handle when multiple index signatures exist (since all index signatures usually get tossed into the same __index symbol, rather than each having their own). Certainly, if the filtered list of applicable index signature declarations is identical to the full list, reusing the original symbol should be OK, and we could probably cache and reuse symbols when they're the same declaration subset across usages.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New approach, as explained by @weswigham

  1. If infos is the same as all the infos available in the type, just return the InternalSymbolName.Index member of the type directly.
  2. If you do have to make a filtered one - cache it for each set of declarations you use. Add a member to SymbolLinks and store the cache on the original Index symbol, keyed by the list of (ids of) declarations in the filtered symbol.

checkQualifiedName(name, CheckMode.Normal);
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/types.ts
Expand Up @@ -4507,6 +4507,7 @@ namespace ts {
/* @internal */ getTypeOfPropertyOfType(type: Type, propertyName: string): Type | undefined;
getIndexInfoOfType(type: Type, kind: IndexKind): IndexInfo | undefined;
getIndexInfosOfType(type: Type): readonly IndexInfo[];
getIndexInfosOfIndexSymbol: (indexSymbol: Symbol) => IndexInfo[];
getSignaturesOfType(type: Type, kind: SignatureKind): readonly Signature[];
getIndexTypeOfType(type: Type, kind: IndexKind): Type | undefined;
/* @internal */ getIndexType(type: Type): Type;
Expand Down Expand Up @@ -5317,6 +5318,7 @@ namespace ts {
isConstructorDeclaredProperty?: boolean; // Property declared through 'this.x = ...' assignment in constructor
tupleLabelDeclaration?: NamedTupleMember | ParameterDeclaration; // Declaration associated with the tuple's label
accessibleChainCache?: ESMap<string, Symbol[] | undefined>;
filteredIndexSymbolCache?: ESMap<string, Symbol> //Symbol with applicable declarations
}

/* @internal */
Expand Down
36 changes: 31 additions & 5 deletions src/services/symbolDisplay.ts
Expand Up @@ -64,6 +64,7 @@ namespace ts.SymbolDisplay {
if (flags & SymbolFlags.SetAccessor) return ScriptElementKind.memberSetAccessorElement;
if (flags & SymbolFlags.Method) return ScriptElementKind.memberFunctionElement;
if (flags & SymbolFlags.Constructor) return ScriptElementKind.constructorImplementationElement;
if (flags & SymbolFlags.Signature) return ScriptElementKind.indexSignatureElement;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SymbolFlags.Signature is also used for call and construct signatures. If tests are passing this might be fine, but I would want to understand why you don’t have to worry about call and construct signatures here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am actually not sure about this. The function returns ScriptElementKind.memberVariableElement ('property') for SymbolFlags.Property which is the other example I was looking at, I want to return ScriptElementKind.indexSignatureElement ('index') for SymbolFlags.Signature which is why I added this here, but I wasn't aware of SymbolFlags.Signature also being used for call and construct signatures.


if (flags & SymbolFlags.Property) {
if (flags & SymbolFlags.Transient && (symbol as TransientSymbol).checkFlags & CheckFlags.Synthetic) {
Expand Down Expand Up @@ -506,19 +507,19 @@ namespace ts.SymbolDisplay {
else {
addPrefixForAnyFunctionOrVar(symbol, symbolKind);
}

// For properties, variables and local vars: show the type
if (symbolKind === ScriptElementKind.memberVariableElement ||
symbolKind === ScriptElementKind.memberGetAccessorElement ||
symbolKind === ScriptElementKind.memberSetAccessorElement ||
symbolKind === ScriptElementKind.jsxAttribute ||
symbolFlags & SymbolFlags.Variable ||
symbolKind === ScriptElementKind.localVariableElement ||
symbolKind === ScriptElementKind.indexSignatureElement ||
isThisExpression) {
displayParts.push(punctuationPart(SyntaxKind.ColonToken));
displayParts.push(spacePart());
// If the type is type parameter, format it specially
if (type.symbol && type.symbol.flags & SymbolFlags.TypeParameter) {
if (type.symbol && type.symbol.flags & SymbolFlags.TypeParameter && symbolKind !== ScriptElementKind.indexSignatureElement) {
const typeParameterParts = mapToDisplayParts(writer => {
const param = typeChecker.typeParameterToDeclaration(type as TypeParameter, enclosingDeclaration, symbolDisplayNodeBuilderFlags)!;
getPrinter().writeNode(EmitHint.Unspecified, param, getSourceFileOfNode(getParseTreeNode(enclosingDeclaration)), writer);
Expand Down Expand Up @@ -639,13 +640,38 @@ namespace ts.SymbolDisplay {
}

function addFullSymbolName(symbolToDisplay: Symbol, enclosingDeclaration?: Node) {
let indexInfos;

if (alias && symbolToDisplay === symbol) {
symbolToDisplay = alias;
}
const fullSymbolDisplayParts = symbolToDisplayParts(typeChecker, symbolToDisplay, enclosingDeclaration || sourceFile, /*meaning*/ undefined,
SymbolFormatFlags.WriteTypeParametersOrArguments | SymbolFormatFlags.UseOnlyExternalAliasing | SymbolFormatFlags.AllowAnyNodeKind);
addRange(displayParts, fullSymbolDisplayParts);
if (symbolKind === ScriptElementKind.indexSignatureElement) {
indexInfos = typeChecker.getIndexInfosOfIndexSymbol(symbolToDisplay);
}

let fullSymbolDisplayParts: SymbolDisplayPart[] = [];
if (symbolToDisplay.flags & SymbolFlags.Signature && indexInfos) {
if (symbolToDisplay.parent) {
fullSymbolDisplayParts = symbolToDisplayParts(typeChecker, symbolToDisplay.parent);
}
fullSymbolDisplayParts.push(punctuationPart(SyntaxKind.OpenBracketToken));
//Needed to handle more than one type of index
indexInfos.forEach((info, i) => {
//Needed to handle template literals
fullSymbolDisplayParts.push(...typeToDisplayParts(typeChecker, info.keyType));
if (i !== indexInfos.length - 1) {
fullSymbolDisplayParts.push(spacePart());
fullSymbolDisplayParts.push(punctuationPart(SyntaxKind.BarToken));
fullSymbolDisplayParts.push(spacePart());
}
});
fullSymbolDisplayParts.push(punctuationPart(SyntaxKind.CloseBracketToken));
}
else {
fullSymbolDisplayParts = symbolToDisplayParts(typeChecker, symbolToDisplay, enclosingDeclaration || sourceFile, /*meaning*/ undefined,
SymbolFormatFlags.WriteTypeParametersOrArguments | SymbolFormatFlags.UseOnlyExternalAliasing | SymbolFormatFlags.AllowAnyNodeKind);
}
addRange(displayParts, fullSymbolDisplayParts);
if (symbol.flags & SymbolFlags.Optional) {
displayParts.push(punctuationPart(SyntaxKind.QuestionToken));
}
Expand Down
1 change: 1 addition & 0 deletions tests/baselines/reference/api/tsserverlibrary.d.ts
Expand Up @@ -2316,6 +2316,7 @@ declare namespace ts {
getPrivateIdentifierPropertyOfType(leftType: Type, name: string, location: Node): Symbol | undefined;
getIndexInfoOfType(type: Type, kind: IndexKind): IndexInfo | undefined;
getIndexInfosOfType(type: Type): readonly IndexInfo[];
getIndexInfosOfIndexSymbol: (indexSymbol: Symbol) => IndexInfo[];
getSignaturesOfType(type: Type, kind: SignatureKind): readonly Signature[];
getIndexTypeOfType(type: Type, kind: IndexKind): Type | undefined;
getBaseTypes(type: InterfaceType): BaseType[];
Expand Down
1 change: 1 addition & 0 deletions tests/baselines/reference/api/typescript.d.ts
Expand Up @@ -2316,6 +2316,7 @@ declare namespace ts {
getPrivateIdentifierPropertyOfType(leftType: Type, name: string, location: Node): Symbol | undefined;
getIndexInfoOfType(type: Type, kind: IndexKind): IndexInfo | undefined;
getIndexInfosOfType(type: Type): readonly IndexInfo[];
getIndexInfosOfIndexSymbol: (indexSymbol: Symbol) => IndexInfo[];
getSignaturesOfType(type: Type, kind: SignatureKind): readonly Signature[];
getIndexTypeOfType(type: Type, kind: IndexKind): Type | undefined;
getBaseTypes(type: InterfaceType): BaseType[];
Expand Down
6 changes: 6 additions & 0 deletions tests/baselines/reference/controlFlowElementAccess2.symbols
Expand Up @@ -13,7 +13,9 @@ if (typeof config['works'] !== 'boolean') {

config.works.prop = 'test'; // ok
>config.works.prop : Symbol(prop, Decl(controlFlowElementAccess2.ts, 1, 30))
>config.works : Symbol(__index, Decl(controlFlowElementAccess2.ts, 0, 23))
>config : Symbol(config, Decl(controlFlowElementAccess2.ts, 0, 13))
>works : Symbol(__index, Decl(controlFlowElementAccess2.ts, 0, 23))
>prop : Symbol(prop, Decl(controlFlowElementAccess2.ts, 1, 30))

config['works'].prop = 'test'; // error, config['works']: boolean | { 'prop': string }
Expand All @@ -22,7 +24,9 @@ if (typeof config['works'] !== 'boolean') {
>prop : Symbol(prop, Decl(controlFlowElementAccess2.ts, 1, 30))
}
if (typeof config.works !== 'boolean') {
>config.works : Symbol(__index, Decl(controlFlowElementAccess2.ts, 0, 23))
>config : Symbol(config, Decl(controlFlowElementAccess2.ts, 0, 13))
>works : Symbol(__index, Decl(controlFlowElementAccess2.ts, 0, 23))

config['works'].prop = 'test'; // error, config['works']: boolean | { 'prop': string }
>config['works'].prop : Symbol(prop, Decl(controlFlowElementAccess2.ts, 1, 30))
Expand All @@ -31,7 +35,9 @@ if (typeof config.works !== 'boolean') {

config.works.prop = 'test'; // ok
>config.works.prop : Symbol(prop, Decl(controlFlowElementAccess2.ts, 1, 30))
>config.works : Symbol(__index, Decl(controlFlowElementAccess2.ts, 0, 23))
>config : Symbol(config, Decl(controlFlowElementAccess2.ts, 0, 13))
>works : Symbol(__index, Decl(controlFlowElementAccess2.ts, 0, 23))
>prop : Symbol(prop, Decl(controlFlowElementAccess2.ts, 1, 30))
}

6 changes: 6 additions & 0 deletions tests/baselines/reference/controlFlowStringIndex.symbols
Expand Up @@ -14,11 +14,15 @@ declare const value: A;
>A : Symbol(A, Decl(controlFlowStringIndex.ts, 0, 0))

if (value.foo !== null) {
>value.foo : Symbol(A.__index, Decl(controlFlowStringIndex.ts, 1, 25))
>value : Symbol(value, Decl(controlFlowStringIndex.ts, 4, 13))
>foo : Symbol(A.__index, Decl(controlFlowStringIndex.ts, 1, 25))

value.foo.toExponential()
>value.foo.toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
>value.foo : Symbol(A.__index, Decl(controlFlowStringIndex.ts, 1, 25))
>value : Symbol(value, Decl(controlFlowStringIndex.ts, 4, 13))
>foo : Symbol(A.__index, Decl(controlFlowStringIndex.ts, 1, 25))
>toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))

value.other // should still be number | null
Expand All @@ -27,6 +31,8 @@ if (value.foo !== null) {
>other : Symbol(other, Decl(controlFlowStringIndex.ts, 0, 10))

value.bar // should still be number | null
>value.bar : Symbol(A.__index, Decl(controlFlowStringIndex.ts, 1, 25))
>value : Symbol(value, Decl(controlFlowStringIndex.ts, 4, 13))
>bar : Symbol(A.__index, Decl(controlFlowStringIndex.ts, 1, 25))
}

Expand Up @@ -105,10 +105,14 @@ delete f.j
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))

delete a.a
>a.a : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional.ts, 12, 14))
>a : Symbol(a, Decl(deleteExpressionMustBeOptional.ts, 21, 13))
>a : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional.ts, 12, 14))

delete a.b
>a.b : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional.ts, 12, 14))
>a : Symbol(a, Decl(deleteExpressionMustBeOptional.ts, 21, 13))
>b : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional.ts, 12, 14))

delete b.a
>b : Symbol(b, Decl(deleteExpressionMustBeOptional.ts, 22, 13))
Expand Down
Expand Up @@ -105,10 +105,14 @@ delete f.j
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))

delete a.a
>a.a : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional.ts, 12, 14))
>a : Symbol(a, Decl(deleteExpressionMustBeOptional.ts, 21, 13))
>a : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional.ts, 12, 14))

delete a.b
>a.b : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional.ts, 12, 14))
>a : Symbol(a, Decl(deleteExpressionMustBeOptional.ts, 21, 13))
>b : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional.ts, 12, 14))

delete b.a
>b : Symbol(b, Decl(deleteExpressionMustBeOptional.ts, 22, 13))
Expand Down
Expand Up @@ -158,10 +158,14 @@ delete g.j
>g : Symbol(g, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 21, 13))

delete a.a
>a.a : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 12, 14))
>a : Symbol(a, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 22, 13))
>a : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 12, 14))

delete a.b
>a.b : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 12, 14))
>a : Symbol(a, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 22, 13))
>b : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 12, 14))

delete b.a
>b : Symbol(b, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 23, 13))
Expand Down
Expand Up @@ -158,10 +158,14 @@ delete g.j
>g : Symbol(g, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 21, 13))

delete a.a
>a.a : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 12, 14))
>a : Symbol(a, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 22, 13))
>a : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 12, 14))

delete a.b
>a.b : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 12, 14))
>a : Symbol(a, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 22, 13))
>b : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 12, 14))

delete b.a
>b : Symbol(b, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 23, 13))
Expand Down
Expand Up @@ -8,7 +8,9 @@

(x) => ({ "1": "one", "2": "two" } as { [key: string]: string }).x;
>x : Symbol(x, Decl(emitAccessExpressionOfCastedObjectLiteralExpressionInArrowFunctionES5.ts, 1, 1))
>({ "1": "one", "2": "two" } as { [key: string]: string }).x : Symbol(__index, Decl(emitAccessExpressionOfCastedObjectLiteralExpressionInArrowFunctionES5.ts, 1, 39))
>"1" : Symbol("1", Decl(emitAccessExpressionOfCastedObjectLiteralExpressionInArrowFunctionES5.ts, 1, 9))
>"2" : Symbol("2", Decl(emitAccessExpressionOfCastedObjectLiteralExpressionInArrowFunctionES5.ts, 1, 21))
>key : Symbol(key, Decl(emitAccessExpressionOfCastedObjectLiteralExpressionInArrowFunctionES5.ts, 1, 41))
>x : Symbol(__index, Decl(emitAccessExpressionOfCastedObjectLiteralExpressionInArrowFunctionES5.ts, 1, 39))

Expand Up @@ -8,7 +8,9 @@

(x) => ({ "1": "one", "2": "two" } as { [key: string]: string }).x;
>x : Symbol(x, Decl(emitAccessExpressionOfCastedObjectLiteralExpressionInArrowFunctionES6.ts, 1, 1))
>({ "1": "one", "2": "two" } as { [key: string]: string }).x : Symbol(__index, Decl(emitAccessExpressionOfCastedObjectLiteralExpressionInArrowFunctionES6.ts, 1, 39))
>"1" : Symbol("1", Decl(emitAccessExpressionOfCastedObjectLiteralExpressionInArrowFunctionES6.ts, 1, 9))
>"2" : Symbol("2", Decl(emitAccessExpressionOfCastedObjectLiteralExpressionInArrowFunctionES6.ts, 1, 21))
>key : Symbol(key, Decl(emitAccessExpressionOfCastedObjectLiteralExpressionInArrowFunctionES6.ts, 1, 41))
>x : Symbol(__index, Decl(emitAccessExpressionOfCastedObjectLiteralExpressionInArrowFunctionES6.ts, 1, 39))

2 changes: 2 additions & 0 deletions tests/baselines/reference/indexSignatures1.symbols
Expand Up @@ -133,7 +133,9 @@ const y1 = dom['data123'];

const y2 = dom.data123;
>y2 : Symbol(y2, Decl(indexSignatures1.ts, 47, 5))
>dom.data123 : Symbol(__index, Decl(indexSignatures1.ts, 45, 18))
>dom : Symbol(dom, Decl(indexSignatures1.ts, 45, 11))
>data123 : Symbol(__index, Decl(indexSignatures1.ts, 45, 18))

// Excess property checking for template pattern index signature

Expand Down
4 changes: 4 additions & 0 deletions tests/baselines/reference/keyofAndIndexedAccess2.symbols
Expand Up @@ -90,7 +90,9 @@ function f2<T extends { [key: string]: number }>(a: { x: number, y: number }, b:
>x : Symbol(x, Decl(keyofAndIndexedAccess2.ts, 12, 53))

b.x;
>b.x : Symbol(__index, Decl(keyofAndIndexedAccess2.ts, 12, 82))
>b : Symbol(b, Decl(keyofAndIndexedAccess2.ts, 12, 77))
>x : Symbol(__index, Decl(keyofAndIndexedAccess2.ts, 12, 82))

c.x;
>c : Symbol(c, Decl(keyofAndIndexedAccess2.ts, 12, 107))
Expand All @@ -105,7 +107,9 @@ function f2<T extends { [key: string]: number }>(a: { x: number, y: number }, b:
>x : Symbol(x, Decl(keyofAndIndexedAccess2.ts, 12, 53))

b.x = 1;
>b.x : Symbol(__index, Decl(keyofAndIndexedAccess2.ts, 12, 82))
>b : Symbol(b, Decl(keyofAndIndexedAccess2.ts, 12, 77))
>x : Symbol(__index, Decl(keyofAndIndexedAccess2.ts, 12, 82))

c.x = 1; // Error, cannot write to index signature through constraint
>c : Symbol(c, Decl(keyofAndIndexedAccess2.ts, 12, 107))
Expand Down
Expand Up @@ -51,7 +51,9 @@ a["foo"]

// access index signature
b.foo;
>b.foo : Symbol(B.__index, Decl(noPropertyAccessFromIndexSignature1.ts, 4, 13))
>b : Symbol(b, Decl(noPropertyAccessFromIndexSignature1.ts, 14, 13))
>foo : Symbol(B.__index, Decl(noPropertyAccessFromIndexSignature1.ts, 4, 13))

b["foo"];
>b : Symbol(b, Decl(noPropertyAccessFromIndexSignature1.ts, 14, 13))
Expand All @@ -68,7 +70,9 @@ c["foo"]

// access index signature
c.bar;
>c.bar : Symbol(C.__index, Decl(noPropertyAccessFromIndexSignature1.ts, 9, 15))
>c : Symbol(c, Decl(noPropertyAccessFromIndexSignature1.ts, 15, 13))
>bar : Symbol(C.__index, Decl(noPropertyAccessFromIndexSignature1.ts, 9, 15))

c["bar"];
>c : Symbol(c, Decl(noPropertyAccessFromIndexSignature1.ts, 15, 13))
Expand All @@ -85,7 +89,9 @@ d?.["foo"]

// optional access index signature
d?.bar;
>d?.bar : Symbol(C.__index, Decl(noPropertyAccessFromIndexSignature1.ts, 9, 15))
>d : Symbol(d, Decl(noPropertyAccessFromIndexSignature1.ts, 16, 13))
>bar : Symbol(C.__index, Decl(noPropertyAccessFromIndexSignature1.ts, 9, 15))

d?.["bar"];
>d : Symbol(d, Decl(noPropertyAccessFromIndexSignature1.ts, 16, 13))
Expand Down