You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
TypeScript: an import resolves to a same-named method of an exported object literal instead of the exported function #2945
import { f } from './m' resolves to a method named f inside an exported object literal in m.ts, instead of m.ts's exported function f, when the object comes first in the file.
// nav.tsexportinterfaceDriver{symbolHref(id: string): string;}exportconsthashDriver: Driver={symbolHref(id){return'#'+id;},// line 3};letdriver: Driver=hashDriver;exportfunctionsymbolHref(id: string): string{returndriver.symbolHref(id);}// line 6// walk.tsimport{symbolHref}from'./nav';exportfunctionwalkTo(id: string){returnsymbolHref(id);}
expected
actual
walkTo calls
symbolHref at nav.ts:6
symbolHref at nav.ts:3 (hashDriver::symbolHref, resolvedBy: import)
Reproduced on main at 31ec908 with CODEGRAPH_KERNEL=0, and on 69af19a with the native kernel too (Linux/WSL2, Node 22.23.2). The same thing happens in this repo: ui/src/lib/walk.ts calls symbolHref/navigate, and __tests__/ui-package.test.ts calls symbolHref/fileHref/mapHref/flowHref. All of them land on hashNavigation's methods in ui/src/lib/navigation.ts (lines 123–187) rather than the exported functions at lines 240–272.
Cause. The object's method is indexed as function symbolHref, isExported = 1, qualifiedName hashDriver::symbolHref (presumably through the object-literal extraction for an exported const). getFileExportIndex keeps the first exported node per name (import-resolver.ts#L279), so the method shadows the real export.
Possible fix. When two exported nodes share a name, let a top-level declaration replace a member:
With that change walkTo links to nav.ts:6, and the 62 __tests__ files matching import/export/reexport/barrel/store/commonjs/require/default pass (490 tests, CODEGRAPH_KERNEL=0). I haven't run the full suite, and a stricter version might keep members out of byName entirely.
Not fixed by #2754 or #2800: I ran this fixture on both heads and the edge still lands on line 3. I also searched open issues and PRs for object-literal methods and import namesakes, and found nothing else that covers it.
Thanks for the report and the precise repro! An import now links to what the module itself exports under that name (a function, an export { … } clause, export default, module.exports or a re-export) rather than to a same-named method of an exported object. The fix is #3076; it's on main and ships in the next release. Re-index JavaScript and TypeScript projects after upgrading.
Activity
fix(resolution): an import no longer lands on a same-named method of …
colbymchenry commentedon Oct 30, 2026
Thanks for the report and the precise repro! An import now links to what the module itself exports under that name (a function, an
export { … }clause,export default,module.exportsor a re-export) rather than to a same-named method of an exported object. The fix is #3076; it's on main and ships in the next release. Re-index JavaScript and TypeScript projects after upgrading.