Skip to content

Commit 998bead

Browse files
author
Andy
authored
Support goto-definition for index signatures (microsoft#23220)
* Support goto-definition for index signatures * Use checker.getIndexInfoOfType * Handle undefined info.declaration
1 parent fb02d67 commit 998bead

File tree

4 files changed

+39
-3
lines changed

4 files changed

+39
-3
lines changed

src/services/goToDefinition.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* @internal */
22
namespace ts.GoToDefinition {
3-
export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile, position: number): DefinitionInfo[] {
3+
export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile, position: number): DefinitionInfo[] | undefined {
44
const reference = getReferenceAtPosition(sourceFile, position, program);
55
if (reference) {
66
return [getDefinitionInfoForFileReference(reference.fileName, reference.file.fileName)];
@@ -29,7 +29,7 @@ namespace ts.GoToDefinition {
2929
// Could not find a symbol e.g. node is string or number keyword,
3030
// or the symbol was an internal symbol and does not have a declaration e.g. undefined symbol
3131
if (!symbol) {
32-
return undefined;
32+
return getDefinitionInfoForIndexSignatures(node, typeChecker);
3333
}
3434

3535
// If this is an alias, and the request came at the declaration location
@@ -157,6 +157,16 @@ namespace ts.GoToDefinition {
157157
return { definitions, textSpan };
158158
}
159159

160+
// At 'x.foo', see if the type of 'x' has an index signature, and if so find its declarations.
161+
function getDefinitionInfoForIndexSignatures(node: Node, checker: TypeChecker): DefinitionInfo[] | undefined {
162+
if (!isPropertyAccessExpression(node.parent) || node.parent.name !== node) return;
163+
const type = checker.getTypeAtLocation(node.parent.expression);
164+
return mapDefined(type.isUnionOrIntersection() ? type.types : [type], nonUnionType => {
165+
const info = checker.getIndexInfoOfType(nonUnionType, IndexKind.String);
166+
return info && info.declaration && createDefinitionFromSignatureDeclaration(checker, info.declaration);
167+
});
168+
}
169+
160170
// Go to the original declaration for cases:
161171
//
162172
// (1) when the aliased symbol was declared in the location(parent).
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/// <reference path='fourslash.ts'/>
2+
3+
////interface I {
4+
//// /*defI*/[x: string]: boolean;
5+
////}
6+
////interface J {
7+
//// /*defJ*/[x: string]: number;
8+
////}
9+
////declare const i: I;
10+
////i.[|/*useI*/foo|];
11+
////declare const ij: I | J;
12+
////ij.[|/*useIJ*/foo|];
13+
14+
verify.goToDefinition("useI", ["defI"]);
15+
verify.goToDefinition("useIJ", ["defI", "defJ"]);
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/// <reference path='fourslash.ts'/>
2+
3+
// Tests that we don't crash for an index signature with no declaration.
4+
5+
// @allowJs: true
6+
7+
// @Filename: /a.js
8+
////const o = {};
9+
////o.[|/*use*/foo|];
10+
11+
verify.goToDefinition("use", []);

tests/cases/fourslash/goToDefinitionRest.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@
88
////let t: Gen;
99
////var { x, ...rest } = t;
1010
////rest.[|/*2*/parent|];
11-
const ranges = test.ranges();
11+
1212
verify.goToDefinition('2', [ '1' ]);

0 commit comments

Comments
 (0)