Skip to content

Commit 3dec819

Browse files
committed
WIP
1 parent d871224 commit 3dec819

File tree

2 files changed

+40
-8
lines changed

2 files changed

+40
-8
lines changed

src/FileIndexer.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,23 @@ export class FileIndexer {
114114

115115
ts.forEachChild(node, child => this.visit(child))
116116
}
117+
118+
// Given the type of `node`, assigns the types of its children. For example,
119+
// when the node is a function declaration, we take the return type of the
120+
// function and assign it to its body.
121+
//
122+
// The reason we do this is because the TypeScript compiler APIs don't seem to
123+
// expose hooks to register when an object type satisfies a nominal type like
124+
// in the example below:
125+
//
126+
// const x: NominalType = {property: 42}
127+
//
128+
// When asking for the type of the `{property: 42}` expression, we get the
129+
// structal type `{property: number}` instead of `NominalType`. Without this
130+
// manual tracking of types, "Go to definition" on `property` does not go
131+
// anywhere because it's the property of a structural/anonymous type. With
132+
// this manual tracking, we know that `property` goes to
133+
// `NominalType.property`.
117134
private updatedAssignedTypeMap(node: ts.Node): void {
118135
if (ts.isVariableDeclaration(node) && node.type && node.initializer) {
119136
this.assignedType.set(node.initializer, {
@@ -209,7 +226,6 @@ export class FileIndexer {
209226
const returnType = this.checker.getReturnTypeOfSignature(callSignature)
210227
this.assignedType.set(node.body, { ...mapped, tpe: returnType })
211228
}
212-
// TODO: handle the case when the assigned type of `() => T` and we assign thebody of the function to type `T`
213229
}
214230
}
215231

@@ -488,6 +504,7 @@ export class FileIndexer {
488504
}
489505
return relationships
490506
}
507+
491508
private scipSymbol(node: ts.Node): ScipSymbol {
492509
const fromCache: ScipSymbol | undefined =
493510
this.globalSymbolTable.get(node) || this.localSymbolTable.get(node)

src/TypeMapper.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -141,20 +141,35 @@ export function getParameterTypes(
141141
)
142142
}
143143

144+
// In some cases, `tpe.symbol.valueDeclaration` is undefined but we can recover
145+
// the correct value declaration by finding the parent of a property. This may
146+
// be caused by a bug in the tsc API where `valueDeclaration` is not correctly
147+
// forwarded for mapped types. Either way, this function fixes an important test
148+
// case in the snapshots. This approach does not work for alias types where the
149+
// property is not a direct child of the alias, but we guard against this case
150+
// by checking that the symbol of the value declaration is the same as the
151+
// symbol of the type.
152+
function correctedValueDeclaration(tpe: ts.Type): ts.Node | undefined {
153+
if (tpe.symbol?.valueDeclaration) {
154+
return tpe.symbol.valueDeclaration
155+
}
156+
for (const property of tpe.getProperties()) {
157+
const parent = property?.valueDeclaration?.parent
158+
if (parent !== undefined) {
159+
return parent
160+
}
161+
}
162+
return undefined
163+
}
164+
144165
export function newTypeMap(
145166
checker: ts.TypeChecker,
146167
old: TypeMapper | undefined,
147168
tpe: ts.Type
148169
): TypeMapper | undefined {
149170
const typeReference = asTypeReference(tpe)
150171
if (typeReference?.typeArguments && typeReference.typeArguments.length > 0) {
151-
const [property] = tpe.getProperties()
152-
if (!property) {
153-
return old
154-
}
155-
const valueDeclaration = tpe.symbol?.valueDeclaration
156-
? tpe.symbol.valueDeclaration
157-
: property?.valueDeclaration?.parent
172+
const valueDeclaration = correctedValueDeclaration(tpe)
158173
if (valueDeclaration) {
159174
const valueDeclarationType = checker.getTypeAtLocation(valueDeclaration)
160175
if (valueDeclarationType.symbol !== tpe.symbol) {

0 commit comments

Comments
 (0)