I’m not sure what the best way is to fix this, but: auto-importing is incredibly helpful. Alas, it only works for named exports. However, imports such as the following are frequent in Node.js and there, you get no help:
import * as path from 'path';
Possible solution: offer an auto-import if:
foo followed by a dot andfoo is the base name of a module.Can you clarify what you're typing and when you'd expect this to show up?
path. (path being an unknown identifier).'path'.But I’m open to anything that helps with import * as: maybe there doesn’t have to be a dot after path. Then auto-importing would be offered for both namespace imports and named imports.
If something is already imported as a namespace, we ought to (but don't currently) prefix a completion with the namespace name, rather than adding a new named import.
As a second issue we might consider adding an option to always make a namespace import even if one doesn't already exist.
As a second issue we might consider adding an option to always make a namespace import even if one doesn't already exist.
I don’t think that that would be useful:
path, both named imports and namespace imports are common.path”. Therefore, I’d prefer it if an IDE would namespace-import path for me when I first mention its name.So the suggestion here is to offer the names of modules in the completion list with an additional action to import them? i.e. path would show up as a completion entry in the global scope.
Yes! But I’m not sure what you mean by “in the global scope”. path would be global-ish, but the suggestion would appear anywhere, independent of scope.
Oh, and it could be complemented by a quick fix offering to namespace-import path whenever that identifier is ever unknown anywhere.
My only worry is the amount of unrelated names we put in the completion list.
My only worry is the amount of unrelated names we put in the completion list.
True, but we already add in every possible named export in a project context.
This just gets very annoying for anything in Node that's a built-in. path, fs, and more are just painful to import. otherwise. Maybe when moduleResolution is calculated as node, we could try
package.json that have a declarationIssue related to this: https://github.com/microsoft/TypeScript/issues/19630
Perhaps TS could suggest namespace imports based on existing imports in the project?
E.g. if the module foo/bar is imported as …
import * as FooBar from 'foo/bar';
… in _other_ modules, then when I type FooBar in _this_ module, suggest importing it using the same import statement as seen in other modules (above). TS would learn from how the same module is imported elsewhere.
Has there been any movement on this? I noticed that VS code now sometimes adds a bracketed name to the module name where the imported function is coming from..
My only worry is the amount of unrelated names we put in the completion list.
Maybe we could we limit this to ambient module declarations, and packages listed in dependencies, devDependencies, and peerDependencies?
Maybe we could we limit this to ambient module declarations, and packages listed in dependencies, devDependencies, and peerDependencies?
That would happen automatically at this point: https://github.com/microsoft/TypeScript/pull/32517
So really the concerns are pretty limited at this point - would the main thing here be to just grab the list of ambients and dependencies and ensure that in the completion list their names
bar-baz becomes barBaz)@foo/bar-baz becomes barBaz)Is this issue specifically about seeing these auto-imports in _completions_ rather than as a code fix (lightbulb) once you type the full module symbol name? I don’t see it noted anywhere in this issue that the latter _does_ work today:

There are a few caveats:
@types/node in your package.json (not just included transitively), _or_ have already imported any other node built-in module in that file.esModuleInterop settings determine whether you get import path from 'path', import * as path from 'path', or import path = require('path')@andrewbranch By “today”, do you mean in VS Code Insiders’ Build? I don’t get the lightbulb in VS Code 1.42.1. (my project meets the requirements you mentioned).
Definitely good enough for my needs, but I wouldn’t mind additionally having completions.
Yeah, I just tried it with TypeScript 3.7.5 in VS Code Insiders, though I think it’s been working for longer than that. To clarify, are you in a TS or JS file? Support in JS files is a little spotty, even for ES imports. If it’s TS, it should definitely be working. If the repo is open source or if you can give me read access to what you’re looking at, I’d be happy to take a look.
Thanks for the offer – much appreciated!
I switched to a public project and here I am indeed getting the lightbulb!
Project: https://github.com/rauschma/enumify
Caveat: If I go to ts/src/index.ts and quick-fix path, I’m getting:
import path = require("path");
This is old TypeScript(?) Neither CommonJS nor ESM. Not sure why.
That’s TypeScript syntax for CommonJS (analogous to const path = require("path")). It’s happening because the typings for path are written as a CommonJS module (export = path is TypeScript syntax for module.exports = path). And while node built-ins _do_ make themselves available as ES modules and CJS modules simultaneously in ways that the DefinitelyTyped typings cannot yet accurately reflect, you’re compiling down to CommonJS, and so those definitions do accurately reflect reality for your project. So, strictly speaking, a CommonJS-equivalent import is the most correct import form given the information available to the compiler.
However, if I’ve learned one thing in this job, it’s that people _hate_ import/require, and no amount of me explaining that it’s really correct makes them feel better about it. So instead of doing that, I’ve been slowly introducing logic that looks for any excuse to prefer a different import form. Namely, if esModuleInterop or allowSyntheticDefaultImports is enabled, you’ll get a default import (import path from 'path') instead. If your module setting is ES2015 or newer, then import/require isn’t allowed (because it’s explicitly CommonJS), so you get a namespace import (import * as path from 'path').
Unfortunately, your code doesn’t match any of those heuristics, and so there’s no reason why the compiler should choose the namespace import over the CommonJS import. So, strict correctness prevails.
Just out of curiosity, if you were writing vanilla JS in ESM, would you use import path from 'path' or import * as path from 'path'?
I’d probably go with:
import * as path from "path";
Since it’s more ESM‑ish and doesn’t rely on the fact that Node.js synthesises the default export for all CommonJS modules.
That said, non‑Node.js built‑ins can only be default‑imported.
Most helpful comment
My only worry is the amount of unrelated names we put in the completion list.