fix(ts): an interface links the interfaces it extends (#2726)

tree-sitter-typescript holds an interface's supertypes in an
extends_type_clause, which neither extractInheritance (wasm) nor the
kernel's extract_inheritance read: a class's extends and implements
became edges, an interface's extends nothing. So an interface had no
place in the type hierarchy, a change to it reached none of the
interfaces built on it, and a call through a composite interface whose
head the receiver typing could not read fell to name matching
(home-assistant/frontend's hass.formatEntityName linked to a namesake
in an unrelated file).

Both engines now emit one extends reference per type of the clause: a
name, a qualified name as written (shapes.Shape), or a generic type by
its name field (Repo for Repo<User>). They resolve as a class's do, so
a package's type stays unresolved, and a namespace import or a module
the repository declares resolves.

A supertype a TS/JS module names without importing it is now its own
declaration or a global one, at a script's top level or in declare
global, never another module's or a namespace's: vscode's interfaces
extending Omit<...> linked to quickInput.ts's export type Omit, and
extends Function to terminal-suggest's Fig.Function.

A call on a TS/JS type whose declaration is known now takes the method
from that declaration's own supertypes. The walk by name, which unions
the supertypes of every same-named type and looks the method up by name
again, follows only classes' supertypes, as before interfaces had any.
Otherwise vscode's receiver.dispose() on an ILocalOtlpHttpReceiver
extends IDisposable reached copilot's own IDisposable, one of eleven,
and stream.on() on a NodeJS.ReadableStream the project's
ReadableStreamEvents.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Colby Mchenry
2026-10-21 03:44:24 +00:00
committed by GitHub
co-authored by Claude Opus 5.5
parent 226ac930de
commit e97012eb31
6 changed files with 659 additions and 2 deletions
+16
View File
@@ -1694,6 +1694,22 @@ impl<'t> Walker<'t> {
}
}
}
// TS `interface Repo<T> extends Base, ns.Shape, Store<T>` — each
// supertype is a `type` of the clause; a `generic_type` is named
// by its `name` field (`Store`, never `Store<T>`).
"extends_type_clause" => {
let mut cursor = child.walk();
let targets: Vec<Node<'t>> = child.children_by_field_name("type", &mut cursor).collect();
for target in targets {
let named = if target.kind() == "generic_type" {
target.child_by_field_name("name").unwrap_or(target)
} else {
target
};
let name = self.text(named).to_string();
self.push_ref(class_row, &name, extends_kind, target);
}
}
// JS `class Foo extends Bar` — class_heritage holds a bare
// identifier without an extends_clause wrapper.
"identifier" | "type_identifier" if node.kind() == "class_heritage" => {