Skip to content

Completion details can’t distinguish between a default export and a named export matching the filename #42871

Closed
@andrewbranch

Description

@andrewbranch

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.

🖼 GIF demonstrating problem

Kapture 2021-02-18 at 14 44 14

🙂 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:

  1. 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 match name.
  2. It’s ambiguous! name is not always the actual name from the exports symbol table; default and export= 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 the default 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?

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScriptDomain: Completion ListsThe issue relates to showing completion lists in an editorFix AvailableA PR has been opened for this issue

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions