-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
types in transitive dependencies causing errors after upgrade from 3.1: The inferred type of ... cannot be named without a reference to #30858
Comments
FYI I have also create a fork of the lerna example from @RyanCavanaugh but with the code for the above modules: https://github.com/ravenscar/learn-a It fails with the same error:
|
Having similar issues on my team when we're writing any new library. If I use some package, lets say, In this specific case,
In the latest Typescript, I need to also need to explicit declare the type of
This is a bit onerous, and feels like it's something the compiler should be able to generate in the worst case. Making This is just one particular example. There have been others since upgrading past 3.1. |
We're getting many examples of this on multiple projects that we're updating to angular 8 (ans as a result TS 3.4) |
Although... Having said that I only get this problem when compiling using angular. It does not happen when I just use tsc |
I see this in a monorepo that uses pnpm to link the packages together. Under Mac OS the project reports a few of these sorts of errors in files A and B, but if I build via a Ubuntu image in Docker then I see the error reported in files C and D. I can work around the issue by adding explicit types at each location mentioned in the errors. |
We're currently intending to get around the error (in our HOCs) by using React Hooks instead of HOCs. But this doesn't help the folks who've got large codebases that need HOCs, or frameworks that are still using that paradigm. |
This error started happening in 7a71887 by @weswigham. It errors if "node_modules" appears in the generated import, as that will probably not work when the .d.ts files are distributed. This is controled by Another repo case: https://github.com/pauldraper/ts-infer-import I ran into this with bazel-contrib/rules_nodejs#1013 . The Bazel build tool doesn't give control over the file layout (makes dependency and heremiticity guarantees easier); so that project uses a path mapping to the location of node_modules. So the import from (Ideally, TypeScript would choose a non-relative path mapping here.) Until TS 3.2, this was not a problem since Bazel users typically do not distribute their declarations via npm. |
In such a scenario, a non-relative mapping does not yet exist as far as the compiler is aware. If |
Correct. A non-relative mapping is not always possible. In the repro case it was, but yes not generally. The code first tries for a node_modules-based non-relative path, and then falls back to non-node_modules relative path, preferring relative. In my case, Bazel was effectively trying to relocate node_modules via a * path mapping. Had it actually been real node_modules, it would have generated a non-relative path and succeeded. But it wasn't, so it didn't. A "solution" for this case would be to try both node_modules non-relative and non-node_modules non-relative paths first. I say "solution" because IDK if it is the best approach. I think Bazel just needs to get more aggressive. Could |
I get there is a workaround in your example for An practical example for us would be we have a module which works with the database Unfortunately because of this bug all the Now I really really really don't think it is at all reasonable for A to need to know about C at all. I don't know if the TS devs are considering this an actual bug and intend to fix it, or just a weird feature of the compiler which has a workaround for people using monorepos. The reason why many people are not experiencing this is because they are using aftermarket typings from the Imagine if there were first party typings for all the database modules, then imagine that knex (quite legitimately) used these types in its own typings e.g. for the db connection setup. Is it reasonable to tell people that despite using knex to isolate themselves from low level database modules they still need to import them all over the place? |
Another point I thought of was that what if I still think there is something fundamentally wrong with how the paths are resolve. I think it should be absolutely fine for A to use B which uses C where C is in the node_modules of B and not A. If this isn't the case then it seems to me that the typescript compiler isn't compliant with the NPM structure. |
It can and does. In fact, you'd find out as much once you started writing the imports by hand once you discovered that the types mismatch (if they do).
Have you considered reexporting C1's support types in C2? That can lead to a cleaner setup.
It's very much not a bug. Your code has an inferred type at some location that is defined in some other package that it does not have direct access to. The compiler needs to serialize a reference to that type. This error is here to get the programmer to resolve that issue, since there's no way for the compiler to do it automatically in a safe way.
A -> B -> C is fine. The issue is that the (would be) generated types imply A -> C. That's no good, and is why the error occurs. |
@weswigham I've come across this a few times, and I agree with this explanation that it's not a bug. But I do think typescript could do something more helpful than throwing an error when it crops up. A dead-simple solution I can think of is, instead of throwing an error, declare the un-nameable transitive dependency type as I've usually come up against this when I'm trying to export a utility function within an internal module of a library, but one that isn't intended to re-exported by the library's Another solution would be to allow I can't speak for others, but I think falling back to
|
This seems to be “fixed” by #33567 (cc @sheetalkamat). I’ve confirmed the repro provided by @ravenscar now compiles without errors (the inferred module specifier from C to A is now I’m not sure if this is actually desirable in a Lerna setup, though—my guess is that you shouldn’t actually want TypeScript resolving cross-package paths as relative. And if that’s the case, it’s clear that what @weswigham is saying is right—there is literally no safe path the compiler can use, so you absolutely should get an error, which should prompt you to re-export the transitive dependencies’ types through the direct dependency, or else declare an explicit dependency upon the transitive dependencies. So I’m really not sure how to call this. It seems like the 3.6 behavior is “working as intended” to protect you from shipping packages with bad paths in their typings, although we’re learning in this issue that it can be painful, and that protection isn’t necessary for folks who aren’t going to publish their individual Lerna packages separately (I guess this is a use case for most of you in this thread?). Now, we’ve eliminated that pain (perhaps inadvertently—it looks like #33567 was considering |
Regression, imo (Cross-project-ref relative specifiers probably? shouldn't be generated for modules? Or maybe just not relative paths that leave the project root? I'm unsure.), but that's probably obvious from my explaination above. |
But both of these things are common in project references that aren’t symlinked into each others’ node_modules. It feels like it’s only because the node_modules symlink exists that we should be clued into the fact that we shouldn’t escape the root. |
So this was a weird one, but I’m going to close this as “fixed” by #33567. For anyone who simply has a symlinked monorepo where they never split up and publish the individual packages, this is a quality of life improvement. If, on the other hand, someone runs into a problem with non-portable paths that is now uncaught due to #33567, we’ll consider more sophisticated logic for catching that problem as a feature request, and at that point we’ll try to implement it without messing up the “my monorepo works fine, don’t make my life harder by giving me errors that aren’t relevant to me” scenario. |
I solved it by move project position to a clean folder which has no parent
will get error:
but if
everything is OK. |
If you want to quickly test a new dependency I can recommend a new feature in npm v7: https://docs.npmjs.com/cli/v7/using-npm/workspaces |
TypeScript Version: 3.4.3
Search Terms:
transitive dependency inferred type cannot be named without a reference
Code
Sorry that this is a Dockerfile, since the problem relates to multiple modules being installed as dependencies to each other it's difficult to express in a single piece of code. There's only 16 lines of code total, near as minimal as I could make it.
https://github.com/ravenscar/ts29221
Expected behavior:
tsc
can compile the codeActual behavior:
tsc
fails with the messge:This used to work fine in TS < 3.2 and seems to have broken since then, looking at the breaking changes I can't see anything mentioned which would apply here.
At first we thought we were experiencing issues due to symlinks created by lerna bootstrap and wanted to create an extremely minimal reproduction based on #29221, however we discovered that symlinks aren't the problem and have produced a Dockerfile to show that:
We also have a Dockerfile showing this working in 3.1:
What happens here is that module
ts29221-a
exports a type definition, modulets29221-b
uses that type definition in the return type of a function, then modulets29221-c
uses that function to assign a value to a const.This is using the new build system, with refs in the tsconfig, and is bootstrapped by lerna.
What is happening here is that when
tsc
is compilingts29221-c
it imports the types fromts29221-b
which in turn imports them fromts29221-a
. It then sees that they types are at a relative position of../b/node_modules/ts29221-a/dist
compared tots29221-c
's package.json.They are actually also at
node_modules/ts29221-b/node_modules/ts29221-a/dist
relative tots29221-c
's package.json.This is for example where they may be if they were installed by a package manager that didn't flatten dependencies (e.g. npm2 or pnpm).
The only way around this is for
c
to somehow know thatb
usesa
and to adda
as a direct dependency ofc
. Then to import the used type definition froma
before importingb
, even thoughc
doesn't directly usea
(so will need a tslint:ignore too).Or do something even worse such as put this workaround at the top of
c/src/index.ts
:I think it is unreasonable for modules to need to know the dependencies of any of their submodules when it comes to types, although that is what we are currently doing in dozens of places.
I understand that the module resolution shows that it will only go up for node_modules but it really seems like something went wrong here as this pretty much makes TS broken for monorepos that use symlinks, if this is intentional then it's hard to imagine how the new build/watch features (which are awesome BTW) are supposed to work when the ts module dependencies are multiple levels deep.
Related Issues:
#29221
#29808
#26985
The text was updated successfully, but these errors were encountered: