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
auto-import favors import from target instead of source #38856
TypeScript Version: 4.0.0-dev.20200529
Verify no issue with vs code version 1.45.1 + typescript vsrion: 3.8
Verify issue with vs code + typescript 3.9.3
still have issue with vs code + typescript 4.0.0-dev20200529
Search Terms:
import / auto import Code
we have project configure as
Expected behavior:
When in visual studio code + typescript 3.8
auto import will prompt me to import as
importfoofrom'sharedlib/src/foo'console.log(foo)
Actual behavior:
On typescript 3.9.3+
first, before compile sharedlib, it can't recognize foo, thus no auto import
after compile, it auto import the js from
now when I add new exportable in sharedlib, I have to compile the package first before I am write reference code from other packages
Because code write before/after ts 3.9 are import from different path even for same module, javascript will treat they as different modules, thus breaks states/singleton, if I didn't manually remove /dist from import
chengB12 can you provide a repository with this problem? I think some important information got lost or mangled when you were distilling it down to a simple case. E.g., I think you’d need in your paths "sharedlib/*": ["../sharedlib/*"], not just the starless version, for any of this to compile under any TypeScript version.
chengB12 thanks! This is helpful. I do see that an auto-import isn’t offered for foo, but I still can’t reproduce it offering to import from sharedlib/dist/src/foo after compiling. Can you provide exact steps on how to reproduce that?
Also, in the non-example version of this, are you using Lerna, yarn workspaces, or any other method of symlinking the packages together within node_modules?
Here is something interesting, I can't reproduce it with bare minimal
our original project having tons of export on ts-sharedlib, and our package1 has tons of import from ts-sharedlib. in this case vs code with ts 3.8 can infer from 'ts-sharedlib/src' and ts 3.9 can infer from 'ts-sharedlib/dist/src'
however, when I trying to strip all other files from package1, leaving only one example, and suddenly, neither ts 3.8 nor ts 3.9 can infer import anymore.
It sounds like vs code can be trained to auto import cross packages given enough success imports
either way, it sounds like a bug to me if bare minimal can't infer imports
When you remove all existing references from package1 to sharedlib, the lack of auto imports is currently expected behavior, tracked in #37812. The paths case is a good test case for #38923. But that’s a really well-understood problem, so the dist thing is much more concerning to me, but I can’t know whether or not it’s really a bug without seeing the whole project. For example, if you currently import sharedlib/dist/src/foo anywhere in package1, you’ll get that as a suggestion:
I can share a screenshot,
You can see, I have existing import from 'ts-sharedlib/src...'
and after I comment correct import line,
the auto-import I got is from 'ts-sharedlib/dist/src'
It’s not just the file that matters, though; it’s every file in the project and every file’s dependencies, those dependencies’ dependencies, and so on 😕. Would you be able to share TS Server logs?
Thanks Andrew Branch (@andrewbranch) not worried it won't be fixed, was just curious for real cause I was trying to think of a case :-P, thanks for the descriptive response though!
The paths are used to remove relative imports, which are extremely painful since our repo is quite massive, and is a fairly common request from people (there are lots of issues around this). It is a common pattern with webpack for example to add a resolve.alias to handle this so that your src dir is always allowed to imported as an absolute.
the transformer plugin is the ideal because it just rewrites the paths to relative at compile time so it all matches up and there is no runtime hit.
lerna would be nice here... unfortunately i was not apart of the original decision when the repo was made and that is quite difficult change atm. we use lerna in a few of the other repos that were made more recently ;-)
vscode also does this - they just do it manually at build time, but they enforce absolute imports across the board IIRC ;-)
Andrew Branch (@andrewbranch) I believe I'm still running into this, even with the current TS version:
Note that this is an import from within the same project. I would expect the import path to be "../message/Constants".
Other suggestions are all kinds of weird:
From top to bottom:
index.d.ts in the current project's root dir, which re-exports from ./Values (this file is copied during the build)
index.ts in the current project's src dir, which re-exports from ./src/Values/index.ts (source file for the 1st suggestion)
index file for the referenced project @zwave-js/core(preferred import, because its the referenced project's main export)
Values.d.ts in the current project's root dir, which re-exports from @zwave-js/core (this file is copied during the build)
Values.ts in the current project's src dir, which re-exports from @zwave-js/core (source file for the 4th suggestion)
Absolute path (relative to baseUrl) to the original source (where suggestion 3 exports from). Using this path would be completely invalid.
Tbh, I haven't figured out a good way to import sources from the current project with a relative path and from referenced projects using their absolute path. Sometimes it works, sometimes it doesn't 🤷♂️
Imports that refer to the target location are working for me, even when the source has not been built and the target location does not exist. And of course such imports work as expected at runtime. This works with just project references, without any need to configure a "paths" entry in tsconfigs.
So a source file can import shared/dist/foo, and TS uses node resolution, finds the hoisted shared package, doesn't find dist/foo, but is able to resolve to the .ts source file (in its original, non-hoisted location) that will eventually produce it.
I do have paths configured, because the directory structure is a bit different than the package names that are released later on. My first problem should is not affected by paths though, since it is an "internal" import.
The 2nd one does go away once there is one import in the current file that points to the correct location. When it is not, I think this heuristic makes sense:
Prefer symbols that are exported from another project's main entry point
In the current project, prefer symbols that are just exported (i.e. at the definition site) over ones that are re-exported
I believe I'm still running into this, even with the current TS version:
AlCalzone can you confirm which nightly you’re using?
My first problem should is not affected by paths though, since it is an "internal" import.
It’s affected by baseUrl. You may want to remove that setting once #40101 is merged. I also plan to explore adding a setting that makes it so that imports within a project prefer relative imports.
That said, I want to keep this thread focused on the original problem—there’s a lot of other auto-import work to be done in this release, and it will get harder for me to track if all the different issues become about auto-imports broadly. The only thing relevant to this issue is the fact that you got the Constants import both from build and from src. If you can definitely reproduce this with a recent nightly, is this an open source repo I could clone to reproduce? That would be very helpful. Thanks!
AlCalzone something in your build produces a bunch of .d.ts files in the root level of packages/zwave-js that import directly from build. These root-level declaration files are not excluded by your tsconfig, so these outputs become future inputs. So, this behavior is expected, although we have #40195 to track adding an error/warning for this, since a lot of people end up in this situation accidentally. I didn’t dig into your build process to understand whether it’s intentional or not in your case.
Activity
andrewbranch commentedon Jun 17, 2020
chengB12 can you provide a repository with this problem? I think some important information got lost or mangled when you were distilling it down to a simple case. E.g., I think you’d need in your paths
"sharedlib/*": ["../sharedlib/*"], not just the starless version, for any of this to compile under any TypeScript version.chengB12 commentedon Jun 17, 2020
Hi, I changed in paths, still same issue
I have created a sample project,
sample.zip
andrewbranch commentedon Jun 18, 2020
chengB12 thanks! This is helpful. I do see that an auto-import isn’t offered for
foo, but I still can’t reproduce it offering to import fromsharedlib/dist/src/fooafter compiling. Can you provide exact steps on how to reproduce that?Also, in the non-example version of this, are you using Lerna, yarn workspaces, or any other method of symlinking the packages together within node_modules?
chengB12 commentedon Jun 18, 2020
Here is something interesting, I can't reproduce it with bare minimal
our original project having tons of export on ts-sharedlib, and our package1 has tons of import from ts-sharedlib. in this case vs code with ts 3.8 can infer from 'ts-sharedlib/src' and ts 3.9 can infer from 'ts-sharedlib/dist/src'
however, when I trying to strip all other files from package1, leaving only one example, and suddenly, neither ts 3.8 nor ts 3.9 can infer import anymore.
It sounds like vs code can be trained to auto import cross packages given enough success imports
either way, it sounds like a bug to me if bare minimal can't infer imports
chengB12 commentedon Jun 18, 2020
Sorry I can't provide whole 'issue-reproducible' repo, if needed, I may be able to provide a few screenshots
andrewbranch commentedon Jun 18, 2020
When you remove all existing references from
package1tosharedlib, the lack of auto imports is currently expected behavior, tracked in #37812. Thepathscase is a good test case for #38923. But that’s a really well-understood problem, so thedistthing is much more concerning to me, but I can’t know whether or not it’s really a bug without seeing the whole project. For example, if you currently importsharedlib/dist/src/fooanywhere inpackage1, you’ll get that as a suggestion:But I don’t think that’s a bug.
chengB12 commentedon Jun 18, 2020
I can share a screenshot,
You can see, I have existing import from 'ts-sharedlib/src...'
and after I comment correct import line,
the auto-import I got is from 'ts-sharedlib/dist/src'
andrewbranch commentedon Jun 18, 2020
It’s not just the file that matters, though; it’s every file in the project and every file’s dependencies, those dependencies’ dependencies, and so on 😕. Would you be able to share TS Server logs?
chengB12 commentedon Jun 18, 2020
We have lint to ensure no code use import xx from 'ts-sharedlib/dist/src...'
it shouldn't comes from existing imports
tsserver.log
26 remaining items
bradennapier commentedon Aug 21, 2020
Thanks Andrew Branch (@andrewbranch) not worried it won't be fixed, was just curious for real cause I was trying to think of a case :-P, thanks for the descriptive response though!
The paths are used to remove relative imports, which are extremely painful since our repo is quite massive, and is a fairly common request from people (there are lots of issues around this). It is a common pattern with
webpackfor example to add aresolve.aliasto handle this so that yoursrcdir is always allowed to imported as an absolute.I accomplish this in typescript by adding https://github.com/zerkalica/zerollup as a plugin, but this issue would occur for anyone using webpack or rollup as example as well, or https://github.com/dividab/tsconfig-paths -- but there are probably around 10-12 packages all to deal with these cases.
eslint plugins also exist specifically for this https://github.com/alexgorbatchev/eslint-import-resolver-typescript
the transformer plugin is the ideal because it just rewrites the paths to relative at compile time so it all matches up and there is no runtime hit.
lerna would be nice here... unfortunately i was not apart of the original decision when the repo was made and that is quite difficult change atm. we use lerna in a few of the other repos that were made more recently ;-)
AlCalzone commentedon Sep 9, 2020
Andrew Branch (@andrewbranch) I believe I'm still running into this, even with the current TS version:

Note that this is an import from within the same project. I would expect the import path to be
"../message/Constants".Other suggestions are all kinds of weird:

From top to bottom:
@zwave-js/core(preferred import, because its the referenced project's main export)@zwave-js/core(this file is copied during the build)@zwave-js/core(source file for the 4th suggestion)Tbh, I haven't figured out a good way to import sources from the current project with a relative path and from referenced projects using their absolute path. Sometimes it works, sometimes it doesn't 🤷♂️
chengB12 commentedon Sep 9, 2020
AlCalzone for me, I solve this issue by
{ paths: { "zwave-js/src": [ "../zwave-js/src/*" ] } }dinofx commentedon Sep 9, 2020
Imports that refer to the target location are working for me, even when the source has not been built and the target location does not exist. And of course such imports work as expected at runtime. This works with just project references, without any need to configure a
"paths"entry in tsconfigs.So a source file can import
shared/dist/foo, and TS uses node resolution, finds the hoistedsharedpackage, doesn't finddist/foo, but is able to resolve to the.tssource file (in its original, non-hoisted location) that will eventually produce it.AlCalzone commentedon Sep 9, 2020
I do have paths configured, because the directory structure is a bit different than the package names that are released later on. My first problem should is not affected by paths though, since it is an "internal" import.
The 2nd one does go away once there is one import in the current file that points to the correct location. When it is not, I think this heuristic makes sense:
chengB12 commentedon Sep 9, 2020
from comment of #40253
this is fixed by checking paths first to look up matches, so changing paths to make what you want it to be recommended in auto-import works for me
andrewbranch commentedon Sep 9, 2020
AlCalzone can you confirm which nightly you’re using?
It’s affected by
baseUrl. You may want to remove that setting once #40101 is merged. I also plan to explore adding a setting that makes it so that imports within a project prefer relative imports.That said, I want to keep this thread focused on the original problem—there’s a lot of other auto-import work to be done in this release, and it will get harder for me to track if all the different issues become about auto-imports broadly. The only thing relevant to this issue is the fact that you got the
Constantsimport both frombuildand fromsrc. If you can definitely reproduce this with a recent nightly, is this an open source repo I could clone to reproduce? That would be very helpful. Thanks!AlCalzone commentedon Sep 9, 2020
20200909
That would be lovely!
Yep :)
npm installpackages/zwave-js/src/lib/commandclass/AlarmSensorCC.tsimport { MessagePriority } from "../message/Constants";- you'll get an error in line 163MessagePriorityandrewbranch commentedon Sep 10, 2020
AlCalzone something in your build produces a bunch of
.d.tsfiles in the root level ofpackages/zwave-jsthat import directly frombuild. These root-level declaration files are not excluded by your tsconfig, so these outputs become future inputs. So, this behavior is expected, although we have #40195 to track adding an error/warning for this, since a lot of people end up in this situation accidentally. I didn’t dig into your build process to understand whether it’s intentional or not in your case.AlCalzone commentedon Sep 11, 2020
Thanks, that explains it. In my case it is intentional, because it simulates Node.js's sub-module exports.
andrewbranch commentedon Sep 11, 2020
In that case, you probably just need to tweak your tsconfig.json include/exclude to make sure the editor doesn’t see those files.
AlCalzone commentedon Sep 12, 2020
Andrew Branch (@andrewbranch) That seems to work :)