Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
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 ObjectType).members) {
Comment thread
danay1999 marked this conversation as resolved.
Outdated
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)!;
}
}
}
}
}
Comment thread
danay1999 marked this conversation as resolved.
Outdated
else {

Copy link
Copy Markdown
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.

@weswigham Wesley Wigham (weswigham) Aug 18, 2022

Copy link
Copy Markdown
Member

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
Copy Markdown
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 Wesley Wigham (@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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Copy Markdown
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
Copy Markdown
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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))
}

Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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))

Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Loading