Skip to content

Commit 25c5e57

Browse files
committed
Return string completions for indexed access types
1 parent 4eb633e commit 25c5e57

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
@@ -2911,7 +2911,7 @@ declare namespace ts {
29112911
function isStringLiteral(node: Node): node is StringLiteral;
29122912
function isJsxText(node: Node): node is JsxText;
29132913
function isRegularExpressionLiteral(node: Node): node is RegularExpressionLiteral;
2914-
function isNoSubstitutionTemplateLiteral(node: Node): node is LiteralExpression;
2914+
function isNoSubstitutionTemplateLiteral(node: Node): node is NoSubstitutionTemplateLiteral;
29152915
function isTemplateHead(node: Node): node is TemplateHead;
29162916
function isTemplateMiddle(node: Node): node is TemplateMiddle;
29172917
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
@@ -2964,7 +2964,7 @@ declare namespace ts {
29642964
function isStringLiteral(node: Node): node is StringLiteral;
29652965
function isJsxText(node: Node): node is JsxText;
29662966
function isRegularExpressionLiteral(node: Node): node is RegularExpressionLiteral;
2967-
function isNoSubstitutionTemplateLiteral(node: Node): node is LiteralExpression;
2967+
function isNoSubstitutionTemplateLiteral(node: Node): node is NoSubstitutionTemplateLiteral;
29682968
function isTemplateHead(node: Node): node is TemplateHead;
29692969
function isTemplateMiddle(node: Node): node is TemplateMiddle;
29702970
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)