-
Notifications
You must be signed in to change notification settings - Fork 12.8k
With project references, some cross-package imports of inferred types are emitted with relative paths #39117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Hello @ecraig12345, this is a duplicate of #38111 I wrote up our solution there. The summary is that when wiring up dependencies, It would be awesome if |
I can reproduce this bug after upgrading TypeScript from version I have a monorepo with: Building
but if I copy and paste |
Inferred module specifiers in d.ts file are suppose to be relative so this current behavior is correct but we could prefer the existing import in the file if it refers to same file and i have a PR #42224 to try that out and see how it works out |
How is this correct if the module is in a different project? Relative inferred module specifiers are a huge problem for consumers of our .d.ts files because it's possible/likely that they just flat-out won't work if the folder structure in the consumer's node_modules is different than our monorepo's internal folder structure. Also, there are other existing cases where the inferred specifier is NOT relative and includes the package name; it's only when you mix in project references that you get the relative inferred specifiers. |
This has nothing to do with project references but path mapping provided. If you remove reference to project, you are going to get same specifier. #26341 made sure that declaration emit uses relative paths all the time. If the paths are in |
Then what is the suggested way to handle this case, where we have project references as well as deep imports into other projects? |
@sheetalkamat 's fix in #42224 looks very good. It helps make declaration emit more intuitive and more controllable by the user, because it steers towards reflecting what the user wrote. It permits adhoc fix-ups by users because, worst case, if a synthetic (inferred) import is in an undesirable form, the user can now add their own preferred alias to the source code to tweak the declaration emit. So it's a big step forward (and I think worth landing), but it would be awesome if we could later come up with a comprehensive solution.
I understand that historically this has been a simple heuristic to determine if a file belongs to an external dependency or not. In future it would be good to avoid relying on this assumption because whilst it's a very popular pattern, In the system I work on, we solve this problem automatically for our users by post-processing the DTS files emitted by TypeScript to mop up any unwanted synthetic relative paths by converting them into a canonical form, i.e. package-prefixed bare specifiers. It works, but it sounds like @ecraig12345 has a similar desire, so maybe it's something that could be solved in TypeScript for everyone.
For use-cases where dependencies do not live inside I think the simplest solution would be for declaration emit to read |
…ulating new one (#42224) * Test case where the wrong path is emitted * If import is used in the file, prefer that import specifier over calculating new one Fixes #39117 * Update Baselines and/or Applied Lint Fixes * When non-relative path is used as user preference, ignore relative paths even if they are from the existing file * Fix test * Add comment Co-authored-by: TypeScript Bot <[email protected]>
Thank you! I would like to test this. Normally the nightly releases appear by 8am UTC, but |
I don't think this issue should be closed--while #42224 fixed the issue in some cases, it won't fix it in cases where the file isn't referenced in another import. |
+1 to @ecraig12345's point. E.g. mui/material-ui#24112 is one of the cases that isn't solved because the symbol is only being used implicitly in the
That sounds like a decent solution, as I imagine it breaks relatively rarely. Could you elaborate on how that post-processing works? Just some clever |
@sheetalkamat Could you re-open this issue since #42232 did not fix all issues? I can confirm that some problematic relative import paths are removed but some are still inserted. Full diff of generated declaration files between Example problematic import that is still generated: |
Can you please open a new issue with the small repro that doesnt get fixed so we can reason about it as part of #42232 |
@sheetalkamat I've seen that you can build an installable version of TypeScript from a PR. If you could do that I can quickly check it on our repo. A small repro might take longer. |
@sheetalkamat Repro was quicker than expected: #42349 |
…ulating new one (microsoft#42224) * Test case where the wrong path is emitted * If import is used in the file, prefer that import specifier over calculating new one Fixes microsoft#39117 * Update Baselines and/or Applied Lint Fixes * When non-relative path is used as user preference, ignore relative paths even if they are from the existing file * Fix test * Add comment Co-authored-by: TypeScript Bot <[email protected]>
* Test where relative import isnt ideal in the declaration emit * use project relative preference for declaration emit Fixes #39117 * Fix incorrect path matching when calculating module specifier * Use correct baseUrl for the module specifier
TypeScript Version: 3.9.5 (also repros with nightly)
Search Terms: project references, declaration files, tsconfig paths, inferred types
Code
The repro requires a monorepo with project references plus
paths
in the tsconfig. Full repro with the problematic compiled output checked in here: https://github.com/ecraig12345/learn-a/tree/inferred-relative-imports (it's fairly minimal but may still include a few settings which turn out to be tangential to the issue, sorry)Here's a summary...
@fluentui/pkg2
depends on@fluentui/pkg1
, and both live in the same monorepo under apackages
folder.pkg2
's tsconfig has a project reference pointing topkg1
, and both build withcomposite: true
.They inherit from a shared tsconfig which has a path config like this (to allow imports directly from the root of each package):
The problem comes when you have a file in one package (
pkg2/src/index.ts
in the repro) which has an implicit/inferred reference to a type from another local project-referenced package.This inferred type need not be stated locally, but it will show up in the declaration file as an inline
import()
.Expected behavior:
Compile each package with
tsc
(or in the repro, runyarn build
from the root).pkg2
'sindex.d.ts
looks like this:Actual behavior:
pkg2
'sindex.d.ts
looks like this, which will break consumers:pkg2/src/index.ts
output also adds ansrc
folder underlib
, which I wouldn't expect (pkg2/lib/src/index.{js,d.ts}
), but this is probably unrelated.Variants:
-b
is added to the build command.rootDir
instead ofinclude
, just different output directory structure.paths
config is moved to each project.Playground Link: can't be shown on playground
Related Issues: didn't see anything else quite like this
The text was updated successfully, but these errors were encountered: