Skip to content
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

The inferred type of "X" cannot be named without a reference to "Y". This is likely not portable. A type annotation is necessary. #42873

Closed
mistic opened this issue Feb 19, 2021 · 136 comments
Assignees
Labels
Bug A bug in TypeScript Fixed A PR has been merged for this issue Rescheduled This issue was previously scheduled to an earlier milestone

Comments

@mistic
Copy link

mistic commented Feb 19, 2021

Bug Report

🔎 Search Terms

inferred type cannot be named, symlink node_modules

🕗 Version & Regression Information

I'm verifying the problem on the [email protected]. I've not tried older versions but at least is also reproducible on the @next version as of today.

It is probably a regression or a corner case related with other issues opened and already closed like:

⏯ Playground Link

Link for a repo where the problem is being reproduced

NOTE: Just clone the repo and run yarn tsc

💻 Code

All the relevant code can be found at https://github.com/mistic/reproduce-typescript-problem-when-symlinking-node_modules

It is just reproducing a similar setup that I had on other project that was generating the problem:

  • node_modules are a symlink to another location that is not a direct parent of the symlinked node_modules
  • we are using types in the compilation from a library where those types are just exported from other one, like for example withRouter within react-router-dom that is just a plain export from the same type on react-router.

🙁 Actual behavior

I got the following error:

error TS2742: The inferred type of 'Nav' cannot be named without a reference to '../../deps/node_modules/@types/react-router'. This is likely not portable. A type annotation is necessary.

8 export const Nav = withRouter(({ history }: NavProps) => {
               ~~~


Found 1 error.

🙂 Expected behavior

I was expecting no error at all and that the typescript compiler was just able to find all the respective modules. I've tried everything that I thought was related like enabled the preserveSymlinks. The only thing that stops the error is importing the withRouter type directly from react-router and not from react-router-dom but that doesn't make very sense because I actually want to use the react-router-dom on a couple of places.

\cc @weswigham @sheetalkamat @andrewbranch because I saw you previously worked to try to solve similar issues.

@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label Feb 19, 2021
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 4.3.0 milestone Feb 19, 2021
@weswigham
Copy link
Member

Hm, it's a bit awkward in your case, since we technically never directly discover that react-router is directly visible from your project folder (our symlink discovery is a bit heuristic based, so we only find them in paths we had to resolve a symlink across to access). If you had a react-router import somewhere in the file already, we'd know we have a lookup available... Hm. @RyanCavanaugh today we don't use a package.json for anything within a TS project, however with the recent changes to node resolution, we really should start considering it (so we can resolve package self names and "imports" maps) - as part of that, we could maybe consider using the dependencies manifest as a list of safe-to-access modules, like how we already use it for autoimports in the language server.

@mistic
Copy link
Author

mistic commented Feb 22, 2021

@weswigham Thanks for looking into the issue. What you wrote makes sense in my head as an explanation about why it is this bug happening. Let me know if I can be useful in any other way to move forward with this one as I really hope we can fix it!

@paynecodes
Copy link

paynecodes commented Jun 18, 2021

I've got a repro which may help with the fix available here: paynecodes/ts-repro-type-annotation-require-symlinks. I don't want to hijack this issue if it's the wrong place, so let me know if a new issue is desirable.

The README lists references to similar issues I was able to dig up.

@RyanCavanaugh RyanCavanaugh added the Rescheduled This issue was previously scheduled to an earlier milestone label Jun 18, 2021
@btakita
Copy link

btakita commented Jun 26, 2021

I have a set of npm packages where "types" points to a *.ts (not a *.d.ts) file. Reason being I can directly jump to the implementation with the IDE. The issue I'm running into is the following:

An npm package B that depends on another npm package A. A factory function obj_ that returns a value with a custom type defined or referenced by pkg A. pkg B has export const obj = obj_(). Typescript compilation is successful. When another package C imports the obj from pkg B, The inferred type of "obj" cannot be named without a reference to "path/to/pkg/A". This is likely not portable. A type annotation is necessary.

This cannot happen. At the very least, it would be useful to have a setting in tsconfig.json for the TS compiler to make pkg B fail compilation unless const obj = obj_() has a type annotation. Otherwise, the pkg B has to be fully built & installed by another pkg C as an npm package to test. Inferring the type across packages (not in rootDir) would be the more ergonomic solution, as long as performance does not suffer.

@weswigham
Copy link
Member

 At the very least, it would be useful to have a setting in tsconfig.json for the TS compiler to make pkg B fail compilation unless const obj = obj_() has a type annotation. 

There is one. declaration: true.

@btakita
Copy link

btakita commented Jun 26, 2021

My understanding of declaration: true is that a *.d.ts file is created. It would be great to navigate directly to the *.ts source.

To support both *.ts & *.d.ts files in an npm package, something like "declarationDir": "dist" is necessary, otherwise, *.ts* files will be imported due to import precedence.

Another minor issue that I have to account for is with single file components which are compiled separate from Typescript. For example a svelte or vue component. These components will need to be copied over to the dist directory during npm run build, since npm does not support links within packages.

These are both minor but annoying issues. Particularly annoying when working with monorepos/multirepos with many packages. It's rare & tooling can fix the build issues. It seems like *.d.ts is useful in having a standard to ensure that type inference works in all cases, but it unfortunately breaks navigation. Of course the tools (VSCode, Jetbrains) would need to address the navigation problem as it stands.

Would it make sense to annotate the path to the source of the *.d.ts file in a comment, like a *.map file?

@weswigham
Copy link
Member

My understanding of declaration: true is that a *.d.ts file is created. It would be great to navigate directly to the *.ts source.

Also set declarationMap: true.

@nwaughachukwuma
Copy link

Check if this works for you: #29808 (comment)

@mistic
Copy link
Author

mistic commented Jul 22, 2021

@weswigham @btakita not related with that initial issue but with your last discussion: declarationMap has also a buggy behaviour when used along sourceRoot (which is vital in some cases) #31873 we are still waiting for a solution on that other issue.

@riordanpawley
Copy link

Check if this works for you: #29808 (comment)

doesn't help in my case. yarn workspaces monorepo setup with
monorepo/pkg1 depending on monorepo/pkg2 & node_modules/pkg1
monorepo/pkg2 depending on node_modules/pkg1
Using same version of external/pkg1

@dustinlacewell
Copy link

dustinlacewell commented Jul 23, 2021

I get this issue in a Rush monorepo where a project depends on cmd-ts. Strangely, it only affects VSCode. I have to do the path alias trick, restart TS, but then it works. An I can remove the path alias. Very strange.

@paynecodes
Copy link

I get this issue throughout many scenarios when using a Rush monorepo. Rush, by default, uses pnpm (pnpm workspaces is recommended). I haven't been able to track down the root cause, but I have scoured this issue tracker and subscribed to many topics hoping someone squashes this.

@InsOpDe
Copy link

InsOpDe commented Aug 26, 2021

Im using a pnpm monorepo and had a similiar problem which I could resolve by setting
baseUrl: "." inside the package tsconfig.json

eventualbuddha added a commit to votingworks/vxsuite that referenced this issue Oct 28, 2021
`react-router-dom` has `withRouter` that passes information via a higher-order component. This is fine, but it has fairly complex types that TS is only happy with when it's a default export. When we change to using named exports this will cause a build error. See microsoft/TypeScript#42873.
eventualbuddha added a commit to votingworks/vxsuite that referenced this issue Oct 28, 2021
`react-router-dom` has `withRouter` that passes information via a higher-order component. This is fine, but it has fairly complex types that TS is only happy with when it's a default export. When we change to using named exports this will cause a build error. See microsoft/TypeScript#42873.
@RyanCavanaugh RyanCavanaugh removed this from the TypeScript 4.5.0 milestone Dec 15, 2021
dcramer added a commit to dcramer/peated that referenced this issue Mar 14, 2024
@babakfp
Copy link

babakfp commented Mar 14, 2024

When is this going to get fixed? Why should anyone disable the declaration option when it's needed? Can Microsoft stop f***ing around and keep working on projects it has started?

@divmgl
Copy link

divmgl commented Mar 15, 2024

While I don't agree with the wording here #42873 (comment) I do agree with the sentiment. It'd be nice if a majority of these "quirks" were ironed out.

I've been running into this problem non-stop with project references in a monorepo. We had to move the tsconfig.json file to the root of the monorepo and stop using project references completely, and things are working relatively well but now the issue is we can't divide compilation per project and the entire project has to be compiled every single time.

@babakfp
Copy link

babakfp commented Mar 15, 2024

@typescript-bot @RyanCavanaugh @jakebailey

Can you get this fixed, please?

@rhuanbarreto
Copy link

For the ones joining the issue recently:

The root cause for this issue is described by this comment: #42873 (comment)

Main issue is due to people using PnPM or Bun, which are installing packages as symlinks instead of copying files. Then Typescript follows the symlink and finds out the referenced file is out of the project root, which triggers the error.

Not sure on how to fix this. But the most important is to know the root cause.

@babakfp
Copy link

babakfp commented Mar 25, 2024

Honestly, I'm not switching to NPM. A trash tool forces you to switch to another trash tool, lol. I don't have free 300mb for every goddamn project to install the same package over and over again!

That sounds like it may not be hard to fix after all! Can't the TypeScript team ask for help by sending a message on social media platforms? This will help find someone to fix this issue. If they can't even do this, it's better if they archive the project and let it die. This way other projects will fill the gap, hopefully! They can even try to financially support other open-source projects because clearly, they can't maintain their projects.

@Bessonov
Copy link

@rhuanbarreto

Main issue is due to people using PnPM or Bun, which are installing packages as symlinks instead of copying files. Then Typescript follows the symlink and finds out the referenced file is out of the project root, which triggers the error.

AFAIK bun uses hardlinks:

Since Bun uses hardlinks to "copy" a module into a project's node_modules directory on Linux, the contents of the package only exist in a single location on disk, greatly reducing the amount of disk space dedicated to node_modules.

https://bun.sh/docs/install/cache#saving-disk-space

babakfp added a commit to babakfp/mdx-svelte that referenced this issue Mar 25, 2024
commit 8006c083ddddf6cba04007e464b1932bc3de8b9f
Author: babakfp <[email protected]>
Date:   Fri Mar 15 15:40:54 2024 -0700

    Added todo, formatted import order, updated config schema.

commit b14eb14ca6b8705d55fd18b7057bcf0cefcbc7e7
Author: babakfp <[email protected]>
Date:   Fri Mar 15 15:34:34 2024 -0700

    Revert "Squashed commit of the following:"

    This reverts commit be62503.

Because of: microsoft/TypeScript#42873
@babakfp
Copy link

babakfp commented Apr 1, 2024

I switched to NPM and the issue still exists!!! (same with PNPM and Bun). I'm using Windows 11.
The people that were saying this only happens when using PNPM and Bun, this they test it? Am I doing something wrong?
About symlinks, I don't understand what they achieve here, no matter which package manager I use, the size of node_modules is (almost) the same!!!

@stereobooster
Copy link

stereobooster commented Apr 4, 2024

In my case I had following issue

error TS2742: The inferred type of cannot be named without a reference to '.pnpm/@[email protected]/node_modules/@types/mdast'. This is likely not portable. A type annotation is necessary.

Code is here https://github.com/stereobooster/braindb/blob/275d52636080ec27acd0a30eff0c9be132d1e437/packages/braindb-core/src/parser.ts#L8-L12

It seems I was able to solve it by requiring type of mdast. I don't need this type, but it seems forces TypeScript to actually find desired type declarations.

// @ts-expect-error
import type { Root } from "mdast";

@theoephraim
Copy link

I think I have a relatively painless solution which may work for some...

So in a case where we have a setup like

  • A is the original library with the unresolvable type
  • B is a helper library which wraps and exposes functionality in a library A
  • C is the end user code, which uses library B instead of interacting with A directly (and I'd like to not even declare the dependency on A)

It seems I'm able to fix the issue by re-exporting the missing type from A in B, even though C will still not import it or use it directly.

so my library in B will include something like

export type { MissingType } from 'A'

and C can continue to interact with B as it was before...

Would be great if this is fixed but this will certainly work for now

@pkerschbaum
Copy link

I think I have a relatively painless solution which may work for some...

So in a case where we have a setup like

  • A is the original library with the unresolvable type
  • B is a helper library which wraps and exposes functionality in a library A
  • C is the end user code, which uses library B instead of interacting with A directly (and I'd like to not even declare the dependency on A)

It seems I'm able to fix the issue by re-exporting the missing type from A in B, even though C will still not import it or use it directly.

so my library in B will include something like

export type { MissingType } from 'A'

and C can continue to interact with B as it was before...

Would be great if this is fixed but this will certainly work for now

This is workaround 3.1 of my "workarounds comment" buried deep in this discussion: #47663 (comment)

@mistic may I ask you to update the issue to include a link to these workarounds? The many upvotes indicate it is/was helpful for many people, and I would like to stop commenting here spamming all issue subscribers just to "resurface" the workarounds :)

@MarvinXu
Copy link

I'm using prisma. Importing type from prisma client seem to fix this error(Even though I'm not using this type)

import { Product } from '@prisma/client';

@Injectable()
export class ProductsService {
  findAll() {
    return this.prisma.product.findMany();
  }
}

@JoaoMosmann
Copy link

I'm using prisma. Importing type from prisma client seem to fix this error(Even though I'm not using this type)

import { Product } from '@prisma/client';

@Injectable()
export class ProductsService {
  findAll() {
    return this.prisma.product.findMany();
  }
}

This indeed works.
For more complex cases where there are loads of types required in different levels, I've added a

import type * as PackageTypes from "package"

@babakfp
Copy link

babakfp commented Apr 11, 2024

TypeScript 💪, LOL

import * as _1 from "../../../node_modules/.pnpm/[email protected]/node_modules/yaml/dist/index.js"
import * as _2 from "../../../node_modules/remark-gfm/lib/index.js"
import * as _3 from "../../../node_modules/.pnpm/[email protected]/node_modules/mdast-util-toc/lib/index.js"
import * as _4 from "../../../node_modules/rehype-slug/lib/index.js"
import * as _5 from "../../../node_modules/rehype-autolink-headings/lib/index.js"
import * as _6 from "../../../node_modules/rehype-external-links/lib/index.js"

When is the TypeScript team going to fix this 4-year-old issue?! @weswigham

@weswigham
Copy link
Member

With #58176 merged, all of the instances of this issue that are actually us not looking up a dependency you actually have available (because of symlinks preventing us from realizing some path equivalences) should be fixed in the next release, barring any funky unforeseen bugs (which, if you think you can demonstrate, please open a new issue for us to consider). Which is what the OP's issue was long, long ago. Other people in this thread... much less so.

That means that so long as you actually have the dependencies your declaration file needs as direct dependencies (in your package.json), we'll be able to autogenerate appropriate dependency names, and no longer emit this error. If you still see this error in TS 5.5 and beyond and come to this thread - I'm sorry, SEO has led you astray. This github issue having floated to the top, above even stackoverflow, for that error message is somewhat unfortunate, but not really in our control.

For the benefit of those searchers, our FAQ will likely be updated to have a detailed explanation for this error by the time you find this, but in short: You really do just need to do what the error says, and write an explicit type annotation on the node the error is marked on. You have an implicit, direct, type-level dependency on an indirect dependency's types, and we can't resolve that issue for you - it's up to you how you want to reach in and get at the innards of your dependencies. Maybe you add whatever the type is coming from as a direct dependency, maybe you write your own equivalent type, maybe there's a winding road through aliases and reexports and conditional infers to get at the type that we can't automatically discern, but you can write as the annotation - whatever works for you.

@weswigham weswigham added Bug A bug in TypeScript Fixed A PR has been merged for this issue and removed Needs Investigation This issue needs a team member to investigate its status. labels Apr 19, 2024
@RyanCavanaugh
Copy link
Member

RyanCavanaugh commented Apr 19, 2024

I'm going to lock this since top-SEO issues do get a lot of drive-by comments that will ultimately hide the helpful above comment. See also this comment for a bit of a longer restatement of this.

If, after trying 5.5 beta (or today's nightly or later) you're still seeing this error in a situation where it seems illegitimate, please log a new issue with a link to a simplified repo that we can use to investigate and we'll take a look.

@microsoft microsoft locked as resolved and limited conversation to collaborators Apr 19, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Bug A bug in TypeScript Fixed A PR has been merged for this issue Rescheduled This issue was previously scheduled to an earlier milestone
Projects
None yet
Development

No branches or pull requests