Support goto-definition for index signatures (#23220)

* Support goto-definition for index signatures

* Use checker.getIndexInfoOfType

* Handle undefined info.declaration
This commit is contained in:
Andy 2018-04-09 12:48:41 -07:00 committed by GitHub
parent fb02d670ff
commit 998beadba2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 39 additions and 3 deletions

View file

@ -1,6 +1,6 @@
/* @internal */
namespace ts.GoToDefinition {
export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile, position: number): DefinitionInfo[] {
export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile, position: number): DefinitionInfo[] | undefined {
const reference = getReferenceAtPosition(sourceFile, position, program);
if (reference) {
return [getDefinitionInfoForFileReference(reference.fileName, reference.file.fileName)];
@ -29,7 +29,7 @@ namespace ts.GoToDefinition {
// Could not find a symbol e.g. node is string or number keyword,
// or the symbol was an internal symbol and does not have a declaration e.g. undefined symbol
if (!symbol) {
return undefined;
return getDefinitionInfoForIndexSignatures(node, typeChecker);
}
// If this is an alias, and the request came at the declaration location
@ -157,6 +157,16 @@ namespace ts.GoToDefinition {
return { definitions, textSpan };
}
// At 'x.foo', see if the type of 'x' has an index signature, and if so find its declarations.
function getDefinitionInfoForIndexSignatures(node: Node, checker: TypeChecker): DefinitionInfo[] | undefined {
if (!isPropertyAccessExpression(node.parent) || node.parent.name !== node) return;
const type = checker.getTypeAtLocation(node.parent.expression);
return mapDefined(type.isUnionOrIntersection() ? type.types : [type], nonUnionType => {
const info = checker.getIndexInfoOfType(nonUnionType, IndexKind.String);
return info && info.declaration && createDefinitionFromSignatureDeclaration(checker, info.declaration);
});
}
// Go to the original declaration for cases:
//
// (1) when the aliased symbol was declared in the location(parent).

View file

@ -0,0 +1,15 @@
/// <reference path='fourslash.ts'/>
////interface I {
//// /*defI*/[x: string]: boolean;
////}
////interface J {
//// /*defJ*/[x: string]: number;
////}
////declare const i: I;
////i.[|/*useI*/foo|];
////declare const ij: I | J;
////ij.[|/*useIJ*/foo|];
verify.goToDefinition("useI", ["defI"]);
verify.goToDefinition("useIJ", ["defI", "defJ"]);

View file

@ -0,0 +1,11 @@
/// <reference path='fourslash.ts'/>
// Tests that we don't crash for an index signature with no declaration.
// @allowJs: true
// @Filename: /a.js
////const o = {};
////o.[|/*use*/foo|];
verify.goToDefinition("use", []);

View file

@ -8,5 +8,5 @@
////let t: Gen;
////var { x, ...rest } = t;
////rest.[|/*2*/parent|];
const ranges = test.ranges();
verify.goToDefinition('2', [ '1' ]);