Skip to content

Commit 8e52224

Browse files
committed
feat: support some most-basic cases from microsoft/TypeScript#49033 (with "static" generics) like:
type B = { foo: 5, bar } const a = <T extends keyof B>(a: T) => {} a('foo')
1 parent 75fe403 commit 8e52224

File tree

1 file changed

+67
-9
lines changed

1 file changed

+67
-9
lines changed

typescript/src/definitions.ts

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,18 @@ export default (proxy: ts.LanguageService, info: ts.server.PluginCreateInfo, c:
66
proxy.getDefinitionAndBoundSpan = (fileName, position) => {
77
const prior = info.languageService.getDefinitionAndBoundSpan(fileName, position)
88
if (!prior) {
9-
if (c('enableFileDefinitions')) {
10-
const sourceFile = info.languageService.getProgram()!.getSourceFile(fileName)!
11-
const node = findChildContainingExactPosition(sourceFile, position)
12-
if (node && ts.isStringLiteral(node) && ['./', '../'].some(str => node.text.startsWith(str))) {
9+
const program = info.languageService.getProgram()!
10+
const sourceFile = program.getSourceFile(fileName)!
11+
const node = findChildContainingExactPosition(sourceFile, position)
12+
if (node && ts.isStringLiteral(node)) {
13+
const textSpanStart = node.pos + node.getLeadingTriviaWidth() + 1 // + 1 for quote
14+
const textSpan = {
15+
start: textSpanStart,
16+
length: node.end - textSpanStart - 1,
17+
}
18+
if (c('enableFileDefinitions') && ['./', '../'].some(str => node.text.startsWith(str))) {
1319
const file = join(fileName, '..', node.text)
1420
if (info.languageServiceHost.fileExists?.(file)) {
15-
const start = node.pos + node.getLeadingTriviaWidth() + 1 // + 1 for quote
16-
const textSpan = {
17-
start,
18-
length: node.end - start - 1,
19-
}
2021
return {
2122
textSpan,
2223
definitions: [
@@ -33,9 +34,66 @@ export default (proxy: ts.LanguageService, info: ts.server.PluginCreateInfo, c:
3334
}
3435
}
3536
}
37+
38+
// thoughts about type definition: no impl here, will be simpler to do this in core
39+
if (ts.isCallExpression(node.parent)) {
40+
const parameterIndex = node.parent.arguments.indexOf(node)
41+
const typeChecker = program.getTypeChecker()
42+
const type = typeChecker.getContextualType(node.parent.expression) ?? typeChecker.getTypeAtLocation(node.parent.expression)
43+
// todo handle union
44+
if (type) {
45+
const getDefinitionsFromKeyofType = (object: ts.Type) => {
46+
const origin = object['origin'] as ts.Type | undefined
47+
// handle union of type?
48+
if (!origin?.isIndexType() || !(origin.type.flags & ts.TypeFlags.Object)) return
49+
const properties = origin.type.getProperties()
50+
const interestedMember = properties?.find(property => property.name === node.text)
51+
if (interestedMember) {
52+
const definitions = (interestedMember.getDeclarations() ?? []).map((declaration: ts.Node) => {
53+
const fileName = declaration.getSourceFile().fileName
54+
if (ts.isPropertySignature(declaration)) declaration = declaration.name
55+
const start = declaration.pos + declaration.getLeadingTriviaWidth()
56+
return {
57+
containerKind: undefined as any,
58+
containerName: '',
59+
name: '',
60+
fileName,
61+
textSpan: { start: start, length: declaration.end - start },
62+
kind: ts.ScriptElementKind.memberVariableElement,
63+
contextSpan: { start: 0, length: 0 },
64+
}
65+
})
66+
return {
67+
textSpan,
68+
definitions,
69+
}
70+
}
71+
return
72+
}
73+
// todo handle unions and string literal
74+
const sig = type.getCallSignatures()[0]
75+
const param = sig?.getParameters()[parameterIndex]
76+
const argType = param && typeChecker.getTypeOfSymbolAtLocation(param, node)
77+
if (argType) {
78+
const definitions = getDefinitionsFromKeyofType(argType)
79+
if (definitions) {
80+
return definitions
81+
}
82+
83+
if (argType.flags & ts.TypeFlags.TypeParameter) {
84+
const param = argType as ts.TypeParameter
85+
const constraint = param.getConstraint()
86+
if (constraint) {
87+
return getDefinitionsFromKeyofType(constraint)
88+
}
89+
}
90+
}
91+
}
92+
}
3693
}
3794
return
3895
}
96+
3997
if (__WEB__) {
4098
// let extension handle it
4199
// TODO failedAliasResolution

0 commit comments

Comments
 (0)