Description
Bug Report
🔎 Search Terms
auto import default
🕗 Version & Regression Information
This has probably been a bug since auto-imports were invented
💻 Code
// @Filename: someModule.ts
export const someModule = 0;
export default 1;
// @Filename: index.ts
someMo/**/
🙁 Actual behavior
Two auto-import completions, but both details resolve to the named export.
🙂 Expected behavior
Two auto-import completions that correctly differentiate between the named export and the default export.
Discussion
The reason this happens is that the info we have to go on in getCompletionDetails
is a really poor starting point for trying to figure out what completion entry we’re talking about. All we have is a name
and source
, where name
is the identifier text you want to insert with the completion, and source
is the symbol name of the module. Notable information we don’t have, because we threw it away at the end of getCompletionsAtPosition
, includes
- the file name of the external module (if the module was an external module—it can also be an ambient module)
- what kind of export the completion came from / what kind of import we expected to use (named, default, CJS, namespace)
- whether the export was found in the main program or the AutoImportProvider
Throwing all of this away has two main consequences:
- It’s way more work than should be necessary to find the right export and module again, because there’s no lookup table for module symbol names. So instead, we randomly loop through every source file and ambient module we know about and check whether its symbol’s name matches
source
. Then we loop through every member/property of its exports seeing if the names we come up with there matchname
. - It’s ambiguous!
name
is not always the actual name from the exports symbol table;default
andexport=
get converted into a valid identifier for the import, which can be the file name (camel-cased). In the example above, the file name substitution for thedefault
gets “shadowed” by the named export.
Fixing this is a near-prerequisite for #31658—it gets extra ugly trying to work around this.
Proposal
Add a new opaquely-typed data
property (named to match the LSP CompletionItem
field that has the same purpose) to protocol.CompletionEntry
to replace source
in what gets sent back to TS Server for getCompletionDetails
. (To transition, editors can continue to send source
as well, and TS Server can continue to use it as a fallback for a while.) Then, TypeScript can add whatever properties we need to that new property.
/cc @mjbvz @uniqueiniquity any concerns about compatibility issues? @DanielRosenwasser will we need to update any other editors?