Skip to content

Commit a08b045

Browse files
danay1999Danay Fernandez Alfonsoandrewbranch
authored
Jsdoc property description (#50269)
* jsdocPropertyDescription * jsdocPropertyDescription * jsdocPropertyDescription * Fixes #47933 * added additional test * added additional example * fixed bug * changed function to only grab the literal type * added additional condition for literals and symbols * added additional test cases * Update src/services/symbolDisplay.ts Co-authored-by: Andrew Branch <andrewbranch@users.noreply.github.com> * addressed PR review * addressed new PR review Co-authored-by: Danay Fernandez Alfonso <t-danayf@microsoft.com> Co-authored-by: Andrew Branch <andrewbranch@users.noreply.github.com>
1 parent 5ba22e0 commit a08b045

38 files changed

Lines changed: 322 additions & 5 deletions

File tree

src/compiler/checker.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,7 @@ namespace ts {
439439
getTypeOfPropertyOfType: (type, name) => getTypeOfPropertyOfType(type, escapeLeadingUnderscores(name)),
440440
getIndexInfoOfType: (type, kind) => getIndexInfoOfType(type, kind === IndexKind.String ? stringType : numberType),
441441
getIndexInfosOfType,
442+
getIndexInfosOfIndexSymbol,
442443
getSignaturesOfType,
443444
getIndexTypeOfType: (type, kind) => getIndexTypeOfType(type, kind === IndexKind.String ? stringType : numberType),
444445
getIndexType: type => getIndexType(type),
@@ -42615,6 +42616,35 @@ namespace ts {
4261542616

4261642617
if (name.kind === SyntaxKind.PropertyAccessExpression) {
4261742618
checkPropertyAccessExpression(name, CheckMode.Normal);
42619+
if (!links.resolvedSymbol) {
42620+
const expressionType = checkExpressionCached(name.expression);
42621+
const infos = getApplicableIndexInfos(expressionType, getLiteralTypeFromPropertyName(name.name));
42622+
if (infos.length && (expressionType as ObjectType).members) {
42623+
const resolved = resolveStructuredTypeMembers(expressionType as ObjectType);
42624+
const symbol = resolved.members.get(InternalSymbolName.Index);
42625+
if (infos === getIndexInfosOfType(expressionType)) {
42626+
links.resolvedSymbol = symbol;
42627+
}
42628+
else if (symbol) {
42629+
const symbolLinks = getSymbolLinks(symbol);
42630+
const declarationList = mapDefined(infos, i => i.declaration);
42631+
const nodeListId = map(declarationList, getNodeId).join(",");
42632+
if (!symbolLinks.filteredIndexSymbolCache) {
42633+
symbolLinks.filteredIndexSymbolCache = new Map();
42634+
}
42635+
if (symbolLinks.filteredIndexSymbolCache.has(nodeListId)) {
42636+
links.resolvedSymbol = symbolLinks.filteredIndexSymbolCache.get(nodeListId)!;
42637+
}
42638+
else {
42639+
const copy = createSymbol(SymbolFlags.Signature, InternalSymbolName.Index);
42640+
copy.declarations = mapDefined(infos, i => i.declaration);
42641+
copy.parent = expressionType.aliasSymbol ? expressionType.aliasSymbol : expressionType.symbol ? expressionType.symbol : getSymbolAtLocation(copy.declarations[0].parent);
42642+
symbolLinks.filteredIndexSymbolCache.set(nodeListId, copy);
42643+
links.resolvedSymbol = symbolLinks.filteredIndexSymbolCache.get(nodeListId)!;
42644+
}
42645+
}
42646+
}
42647+
}
4261842648
}
4261942649
else {
4262042650
checkQualifiedName(name, CheckMode.Normal);

src/compiler/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4557,6 +4557,7 @@ namespace ts {
45574557
/* @internal */ getTypeOfPropertyOfType(type: Type, propertyName: string): Type | undefined;
45584558
getIndexInfoOfType(type: Type, kind: IndexKind): IndexInfo | undefined;
45594559
getIndexInfosOfType(type: Type): readonly IndexInfo[];
4560+
getIndexInfosOfIndexSymbol: (indexSymbol: Symbol) => IndexInfo[];
45604561
getSignaturesOfType(type: Type, kind: SignatureKind): readonly Signature[];
45614562
getIndexTypeOfType(type: Type, kind: IndexKind): Type | undefined;
45624563
/* @internal */ getIndexType(type: Type): Type;
@@ -5373,6 +5374,7 @@ namespace ts {
53735374
isConstructorDeclaredProperty?: boolean; // Property declared through 'this.x = ...' assignment in constructor
53745375
tupleLabelDeclaration?: NamedTupleMember | ParameterDeclaration; // Declaration associated with the tuple's label
53755376
accessibleChainCache?: ESMap<string, Symbol[] | undefined>;
5377+
filteredIndexSymbolCache?: ESMap<string, Symbol> //Symbol with applicable declarations
53765378
}
53775379

53785380
/* @internal */

src/services/symbolDisplay.ts

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ namespace ts.SymbolDisplay {
6464
if (flags & SymbolFlags.SetAccessor) return ScriptElementKind.memberSetAccessorElement;
6565
if (flags & SymbolFlags.Method) return ScriptElementKind.memberFunctionElement;
6666
if (flags & SymbolFlags.Constructor) return ScriptElementKind.constructorImplementationElement;
67+
if (flags & SymbolFlags.Signature) return ScriptElementKind.indexSignatureElement;
6768

6869
if (flags & SymbolFlags.Property) {
6970
if (flags & SymbolFlags.Transient && (symbol as TransientSymbol).checkFlags & CheckFlags.Synthetic) {
@@ -506,19 +507,19 @@ namespace ts.SymbolDisplay {
506507
else {
507508
addPrefixForAnyFunctionOrVar(symbol, symbolKind);
508509
}
509-
510510
// For properties, variables and local vars: show the type
511511
if (symbolKind === ScriptElementKind.memberVariableElement ||
512512
symbolKind === ScriptElementKind.memberGetAccessorElement ||
513513
symbolKind === ScriptElementKind.memberSetAccessorElement ||
514514
symbolKind === ScriptElementKind.jsxAttribute ||
515515
symbolFlags & SymbolFlags.Variable ||
516516
symbolKind === ScriptElementKind.localVariableElement ||
517+
symbolKind === ScriptElementKind.indexSignatureElement ||
517518
isThisExpression) {
518519
displayParts.push(punctuationPart(SyntaxKind.ColonToken));
519520
displayParts.push(spacePart());
520521
// If the type is type parameter, format it specially
521-
if (type.symbol && type.symbol.flags & SymbolFlags.TypeParameter) {
522+
if (type.symbol && type.symbol.flags & SymbolFlags.TypeParameter && symbolKind !== ScriptElementKind.indexSignatureElement) {
522523
const typeParameterParts = mapToDisplayParts(writer => {
523524
const param = typeChecker.typeParameterToDeclaration(type as TypeParameter, enclosingDeclaration, symbolDisplayNodeBuilderFlags)!;
524525
getPrinter().writeNode(EmitHint.Unspecified, param, getSourceFileOfNode(getParseTreeNode(enclosingDeclaration)), writer);
@@ -639,13 +640,38 @@ namespace ts.SymbolDisplay {
639640
}
640641

641642
function addFullSymbolName(symbolToDisplay: Symbol, enclosingDeclaration?: Node) {
643+
let indexInfos;
644+
642645
if (alias && symbolToDisplay === symbol) {
643646
symbolToDisplay = alias;
644647
}
645-
const fullSymbolDisplayParts = symbolToDisplayParts(typeChecker, symbolToDisplay, enclosingDeclaration || sourceFile, /*meaning*/ undefined,
646-
SymbolFormatFlags.WriteTypeParametersOrArguments | SymbolFormatFlags.UseOnlyExternalAliasing | SymbolFormatFlags.AllowAnyNodeKind);
647-
addRange(displayParts, fullSymbolDisplayParts);
648+
if (symbolKind === ScriptElementKind.indexSignatureElement) {
649+
indexInfos = typeChecker.getIndexInfosOfIndexSymbol(symbolToDisplay);
650+
}
648651

652+
let fullSymbolDisplayParts: SymbolDisplayPart[] = [];
653+
if (symbolToDisplay.flags & SymbolFlags.Signature && indexInfos) {
654+
if (symbolToDisplay.parent) {
655+
fullSymbolDisplayParts = symbolToDisplayParts(typeChecker, symbolToDisplay.parent);
656+
}
657+
fullSymbolDisplayParts.push(punctuationPart(SyntaxKind.OpenBracketToken));
658+
//Needed to handle more than one type of index
659+
indexInfos.forEach((info, i) => {
660+
//Needed to handle template literals
661+
fullSymbolDisplayParts.push(...typeToDisplayParts(typeChecker, info.keyType));
662+
if (i !== indexInfos.length - 1) {
663+
fullSymbolDisplayParts.push(spacePart());
664+
fullSymbolDisplayParts.push(punctuationPart(SyntaxKind.BarToken));
665+
fullSymbolDisplayParts.push(spacePart());
666+
}
667+
});
668+
fullSymbolDisplayParts.push(punctuationPart(SyntaxKind.CloseBracketToken));
669+
}
670+
else {
671+
fullSymbolDisplayParts = symbolToDisplayParts(typeChecker, symbolToDisplay, enclosingDeclaration || sourceFile, /*meaning*/ undefined,
672+
SymbolFormatFlags.WriteTypeParametersOrArguments | SymbolFormatFlags.UseOnlyExternalAliasing | SymbolFormatFlags.AllowAnyNodeKind);
673+
}
674+
addRange(displayParts, fullSymbolDisplayParts);
649675
if (symbol.flags & SymbolFlags.Optional) {
650676
displayParts.push(punctuationPart(SyntaxKind.QuestionToken));
651677
}

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2316,6 +2316,7 @@ declare namespace ts {
23162316
getPrivateIdentifierPropertyOfType(leftType: Type, name: string, location: Node): Symbol | undefined;
23172317
getIndexInfoOfType(type: Type, kind: IndexKind): IndexInfo | undefined;
23182318
getIndexInfosOfType(type: Type): readonly IndexInfo[];
2319+
getIndexInfosOfIndexSymbol: (indexSymbol: Symbol) => IndexInfo[];
23192320
getSignaturesOfType(type: Type, kind: SignatureKind): readonly Signature[];
23202321
getIndexTypeOfType(type: Type, kind: IndexKind): Type | undefined;
23212322
getBaseTypes(type: InterfaceType): BaseType[];

tests/baselines/reference/api/typescript.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2316,6 +2316,7 @@ declare namespace ts {
23162316
getPrivateIdentifierPropertyOfType(leftType: Type, name: string, location: Node): Symbol | undefined;
23172317
getIndexInfoOfType(type: Type, kind: IndexKind): IndexInfo | undefined;
23182318
getIndexInfosOfType(type: Type): readonly IndexInfo[];
2319+
getIndexInfosOfIndexSymbol: (indexSymbol: Symbol) => IndexInfo[];
23192320
getSignaturesOfType(type: Type, kind: SignatureKind): readonly Signature[];
23202321
getIndexTypeOfType(type: Type, kind: IndexKind): Type | undefined;
23212322
getBaseTypes(type: InterfaceType): BaseType[];

tests/baselines/reference/controlFlowElementAccess2.symbols

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ if (typeof config['works'] !== 'boolean') {
1313

1414
config.works.prop = 'test'; // ok
1515
>config.works.prop : Symbol(prop, Decl(controlFlowElementAccess2.ts, 1, 30))
16+
>config.works : Symbol(__index, Decl(controlFlowElementAccess2.ts, 0, 23))
1617
>config : Symbol(config, Decl(controlFlowElementAccess2.ts, 0, 13))
18+
>works : Symbol(__index, Decl(controlFlowElementAccess2.ts, 0, 23))
1719
>prop : Symbol(prop, Decl(controlFlowElementAccess2.ts, 1, 30))
1820

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

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

3236
config.works.prop = 'test'; // ok
3337
>config.works.prop : Symbol(prop, Decl(controlFlowElementAccess2.ts, 1, 30))
38+
>config.works : Symbol(__index, Decl(controlFlowElementAccess2.ts, 0, 23))
3439
>config : Symbol(config, Decl(controlFlowElementAccess2.ts, 0, 13))
40+
>works : Symbol(__index, Decl(controlFlowElementAccess2.ts, 0, 23))
3541
>prop : Symbol(prop, Decl(controlFlowElementAccess2.ts, 1, 30))
3642
}
3743

tests/baselines/reference/controlFlowStringIndex.symbols

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,15 @@ declare const value: A;
1414
>A : Symbol(A, Decl(controlFlowStringIndex.ts, 0, 0))
1515

1616
if (value.foo !== null) {
17+
>value.foo : Symbol(A.__index, Decl(controlFlowStringIndex.ts, 1, 25))
1718
>value : Symbol(value, Decl(controlFlowStringIndex.ts, 4, 13))
19+
>foo : Symbol(A.__index, Decl(controlFlowStringIndex.ts, 1, 25))
1820

1921
value.foo.toExponential()
2022
>value.foo.toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
23+
>value.foo : Symbol(A.__index, Decl(controlFlowStringIndex.ts, 1, 25))
2124
>value : Symbol(value, Decl(controlFlowStringIndex.ts, 4, 13))
25+
>foo : Symbol(A.__index, Decl(controlFlowStringIndex.ts, 1, 25))
2226
>toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
2327

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

2933
value.bar // should still be number | null
34+
>value.bar : Symbol(A.__index, Decl(controlFlowStringIndex.ts, 1, 25))
3035
>value : Symbol(value, Decl(controlFlowStringIndex.ts, 4, 13))
36+
>bar : Symbol(A.__index, Decl(controlFlowStringIndex.ts, 1, 25))
3137
}
3238

tests/baselines/reference/deleteExpressionMustBeOptional(strict=false).symbols

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,14 @@ delete f.j
105105
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))
106106

107107
delete a.a
108+
>a.a : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional.ts, 12, 14))
108109
>a : Symbol(a, Decl(deleteExpressionMustBeOptional.ts, 21, 13))
110+
>a : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional.ts, 12, 14))
109111

110112
delete a.b
113+
>a.b : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional.ts, 12, 14))
111114
>a : Symbol(a, Decl(deleteExpressionMustBeOptional.ts, 21, 13))
115+
>b : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional.ts, 12, 14))
112116

113117
delete b.a
114118
>b : Symbol(b, Decl(deleteExpressionMustBeOptional.ts, 22, 13))

tests/baselines/reference/deleteExpressionMustBeOptional(strict=true).symbols

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,14 @@ delete f.j
105105
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))
106106

107107
delete a.a
108+
>a.a : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional.ts, 12, 14))
108109
>a : Symbol(a, Decl(deleteExpressionMustBeOptional.ts, 21, 13))
110+
>a : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional.ts, 12, 14))
109111

110112
delete a.b
113+
>a.b : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional.ts, 12, 14))
111114
>a : Symbol(a, Decl(deleteExpressionMustBeOptional.ts, 21, 13))
115+
>b : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional.ts, 12, 14))
112116

113117
delete b.a
114118
>b : Symbol(b, Decl(deleteExpressionMustBeOptional.ts, 22, 13))

tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=false).symbols

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,14 @@ delete g.j
158158
>g : Symbol(g, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 21, 13))
159159

160160
delete a.a
161+
>a.a : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 12, 14))
161162
>a : Symbol(a, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 22, 13))
163+
>a : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 12, 14))
162164

163165
delete a.b
166+
>a.b : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 12, 14))
164167
>a : Symbol(a, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 22, 13))
168+
>b : Symbol(AA.__index, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 12, 14))
165169

166170
delete b.a
167171
>b : Symbol(b, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 23, 13))

0 commit comments

Comments
 (0)