Skip to content

Commit 1041f09

Browse files
Merge pull request microsoft#20941 from mariusschulz/stringCompletionsForIndexedAccessTypes
Return string completions for indexed access types
2 parents 966fa16 + 25c5e57 commit 1041f09

File tree

5 files changed

+31
-8
lines changed

5 files changed

+31
-8
lines changed

src/compiler/utilities.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4403,7 +4403,7 @@ namespace ts {
44034403
return node.kind === SyntaxKind.RegularExpressionLiteral;
44044404
}
44054405

4406-
export function isNoSubstitutionTemplateLiteral(node: Node): node is LiteralExpression {
4406+
export function isNoSubstitutionTemplateLiteral(node: Node): node is NoSubstitutionTemplateLiteral {
44074407
return node.kind === SyntaxKind.NoSubstitutionTemplateLiteral;
44084408
}
44094409

src/services/completions.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,8 @@ namespace ts.Completions {
264264
// }
265265
// let a: A;
266266
// a['/*completion position*/']
267-
return getStringLiteralCompletionEntriesFromElementAccess(node.parent, typeChecker, compilerOptions.target, log);
267+
const type = typeChecker.getTypeAtLocation(node.parent.expression);
268+
return getStringLiteralCompletionEntriesFromElementAccessOrIndexedAccess(node, type, typeChecker, compilerOptions.target, log);
268269
}
269270
else if (node.parent.kind === SyntaxKind.ImportDeclaration || node.parent.kind === SyntaxKind.ExportDeclaration
270271
|| isRequireCall(node.parent, /*checkArgumentIsStringLiteral*/ false) || isImportCall(node.parent)
@@ -278,6 +279,16 @@ namespace ts.Completions {
278279
const entries = PathCompletions.getStringLiteralCompletionsFromModuleNames(node, compilerOptions, host, typeChecker);
279280
return pathCompletionsInfo(entries);
280281
}
282+
else if (isIndexedAccessTypeNode(node.parent.parent)) {
283+
// Get all apparent property names
284+
// i.e. interface Foo {
285+
// foo: string;
286+
// bar: string;
287+
// }
288+
// let x: Foo["/*completion position*/"]
289+
const type = typeChecker.getTypeFromTypeNode(node.parent.parent.objectType);
290+
return getStringLiteralCompletionEntriesFromElementAccessOrIndexedAccess(node, type, typeChecker, compilerOptions.target, log);
291+
}
281292
else {
282293
const argumentInfo = SignatureHelp.getImmediatelyContainingArgumentInfo(node, position, sourceFile);
283294
if (argumentInfo) {
@@ -334,11 +345,10 @@ namespace ts.Completions {
334345
return undefined;
335346
}
336347

337-
function getStringLiteralCompletionEntriesFromElementAccess(node: ElementAccessExpression, typeChecker: TypeChecker, target: ScriptTarget, log: Log): CompletionInfo | undefined {
338-
const type = typeChecker.getTypeAtLocation(node.expression);
348+
function getStringLiteralCompletionEntriesFromElementAccessOrIndexedAccess(stringLiteralNode: StringLiteral | NoSubstitutionTemplateLiteral, type: Type, typeChecker: TypeChecker, target: ScriptTarget, log: Log): CompletionInfo | undefined {
339349
const entries: CompletionEntry[] = [];
340350
if (type) {
341-
getCompletionEntriesFromSymbols(type.getApparentProperties(), entries, node, /*performCharacterChecks*/ false, typeChecker, target, log, /*allowStringLiteral*/ true);
351+
getCompletionEntriesFromSymbols(type.getApparentProperties(), entries, stringLiteralNode, /*performCharacterChecks*/ false, typeChecker, target, log, /*allowStringLiteral*/ true);
342352
if (entries.length) {
343353
return { isGlobalCompletion: false, isMemberCompletion: true, isNewIdentifierLocation: true, entries };
344354
}
@@ -1583,7 +1593,7 @@ namespace ts.Completions {
15831593
switch (contextToken.kind) {
15841594
case SyntaxKind.OpenParenToken:
15851595
case SyntaxKind.CommaToken:
1586-
return isConstructorDeclaration(contextToken.parent) && contextToken.parent;
1596+
return isConstructorDeclaration(contextToken.parent) && contextToken.parent;
15871597

15881598
default:
15891599
if (isConstructorParameterCompletion(contextToken)) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2912,7 +2912,7 @@ declare namespace ts {
29122912
function isStringLiteral(node: Node): node is StringLiteral;
29132913
function isJsxText(node: Node): node is JsxText;
29142914
function isRegularExpressionLiteral(node: Node): node is RegularExpressionLiteral;
2915-
function isNoSubstitutionTemplateLiteral(node: Node): node is LiteralExpression;
2915+
function isNoSubstitutionTemplateLiteral(node: Node): node is NoSubstitutionTemplateLiteral;
29162916
function isTemplateHead(node: Node): node is TemplateHead;
29172917
function isTemplateMiddle(node: Node): node is TemplateMiddle;
29182918
function isTemplateTail(node: Node): node is TemplateTail;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2965,7 +2965,7 @@ declare namespace ts {
29652965
function isStringLiteral(node: Node): node is StringLiteral;
29662966
function isJsxText(node: Node): node is JsxText;
29672967
function isRegularExpressionLiteral(node: Node): node is RegularExpressionLiteral;
2968-
function isNoSubstitutionTemplateLiteral(node: Node): node is LiteralExpression;
2968+
function isNoSubstitutionTemplateLiteral(node: Node): node is NoSubstitutionTemplateLiteral;
29692969
function isTemplateHead(node: Node): node is TemplateHead;
29702970
function isTemplateMiddle(node: Node): node is TemplateMiddle;
29712971
function isTemplateTail(node: Node): node is TemplateTail;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/// <reference path='fourslash.ts'/>
2+
3+
////interface Foo {
4+
//// foo: string;
5+
//// bar: string;
6+
////}
7+
////
8+
////let x: Foo["/*1*/"]
9+
10+
goTo.marker("1");
11+
verify.completionListContains("foo");
12+
verify.completionListContains("bar");
13+
verify.completionListCount(2);

0 commit comments

Comments
 (0)