Skip to content

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

Description

@mistic

Bug Report

🔎 Search Terms

inferred type cannot be named, symlink node_modules

🕗 Version & Regression Information

I'm verifying the problem on the typescript@4.1.3. 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 Wesley Wigham (@weswigham) Sheetal Nandi (@sheetalkamat) Andrew Branch (@andrewbranch) because I saw you previously worked to try to solve similar issues.

Activity

  1. weswigham commented on Feb 19, 2021

    @weswigham
    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. Ryan Cavanaugh (@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.

  2. mistic commented on Feb 22, 2021

    @mistic
    Author

    Wesley Wigham (@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!

  3. jarrodpayne commented on Jun 18, 2021

    @jarrodpayne

    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.

  4. btakita commented on Jun 26, 2021

    @btakita

    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.

  5. weswigham commented on Jun 26, 2021

    @weswigham
    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.

  6. btakita commented on Jun 26, 2021

    @btakita

    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?

  7. weswigham commented on Jun 26, 2021

    @weswigham
    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.

  8. 165 remaining items

  9. babakfp commented on Apr 1, 2024

    @babakfp

    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!!!

  10. stereobooster commented on Apr 4, 2024

    @stereobooster

    In my case I had following issue

    error TS2742: The inferred type of cannot be named without a reference to '.pnpm/@types+mdast@4.0.3/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";
  11. theoephraim commented on Apr 6, 2024

    @theoephraim

    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

  12. patricktree commented on Apr 7, 2024

    @patricktree

    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)

    Tiago Costa (@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 :)

  13. MarvinXu commented on Apr 10, 2024

    @MarvinXu

    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();
      }
    }
  14. JoaoMosmann commented on Apr 10, 2024

    @JoaoMosmann

    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"
  15. babakfp commented on Apr 11, 2024

    @babakfp

    TypeScript 💪, LOL

    import * as _1 from "../../../node_modules/.pnpm/yaml@2.4.1/node_modules/yaml/dist/index.js"
    import * as _2 from "../../../node_modules/remark-gfm/lib/index.js"
    import * as _3 from "../../../node_modules/.pnpm/mdast-util-toc@7.0.0/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?! Wesley Wigham (@weswigham)

  16. weswigham commented on Apr 19, 2024

    @weswigham
    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.

  17. added
    BugA bug in TypeScript
    FixedA PR has been merged for this issue
    and removed
    Needs InvestigationThis issue needs a team member to investigate its status.
    on Apr 19, 2024
  18. RyanCavanaugh commented on Apr 19, 2024

    @RyanCavanaugh
    Member

    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.

  19. locked as resolved and limited conversation to collaborators on Apr 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

BugA bug in TypeScriptFixedA PR has been merged for this issueRescheduledThis issue was previously scheduled to an earlier milestone

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions