TypeScript: "The inferred type of X cannot be named without a reference to Y" (TS2742) occurs when multiple modules with the same package ID are resolved
Bug Report
🔎 Search Terms
- TS2742
- cannot be named without a reference
🕗 Version & Regression Information
Problems occurs with 4.5.x and 4.6.x and most likely earlier versions (I’ve tried a few other versions). It stills occurs on 4.7.0-dev.20220321
.
⏯ Playground Link
I’ve created minimal repository that shows the problem: https://github.com/renke/typescript-package-id-merge-repro
The problem occurs when using pnpm (due to the modules layout it uses). No problems occur when using npm/yarn.
To reproduce the problem run pnpm install
and then pnpm check
pnpx tsc -b
.
💻 Code
I don’t think the code itself matters to much except from the fact that it in fact does not have explicit type annotations (which is kind of the idea when using zod and by extension @renke/vommer).
import { vod } from "@renke/vommer";
import { z } from "zod";
export const UserId = vod("UserId", z.string());
export type UserId = z.infer<typeof UserId>;
export const Email = vod("Email", z.string().min(0));
export type Email = z.infer<typeof Email>;
export const User = vod(
"User",
z.object({
id: UserId,
email: Email,
})
);
export type User = z.infer<typeof User>;
🙁 Actual behavior
The following error occurs when trying to build a composite TypeScript project (same happens when just using declaration: true
).
The inferred type of 'User' cannot be named without a reference to '.pnpm/@renke+vo@0.2.0/node_modules/@renke/vo'. This is likely not portable. A type annotation is necessary.
The dependency tree of @renke/vommer
@renke/vommer 0.2.0
├── @renke/vo 0.2.0
└─┬ @renke/vod 0.2.0
└── @renke/vo 0.2.0
Looking at the resolution trace TypeScript tries to resolve @renke/vo
two times the first time from @renke/vommer
and the second time from @renke/vod
. Both end up having the package ID @renke/vo/dist/index.d.ts@0.2.0
.
Using "preserveSymlinks": true
doesn’t solve the problem in so far that the error disappears but the type is inferred as any, because the dependencies of @renke/vommer
are not found. Also I don’t actually want to use it.
🙂 Expected behavior
The error should not occur when there are two (or more) modules that have the same resolved package ID. It would make sense for the error to occur when they have different versions.
About this issue
- Original URL
- State: open
- Created 2 years ago
- Reactions: 143
- Comments: 98 (3 by maintainers)
Commits related to this issue
- fix(package): fixed ts2742 - 더 확실한 해결방법을 찾았다. - https://github.com/microsoft/TypeScript/issues/47663 - 추가로 Carousel에서 초기에 숫자가 나오는 현상을 해결했다. - Main의 padding이 잘못 조정되는 현상을 해결했다. — committed to seeyouletter/seeyouletter-fe by JengYoung a year ago
- fix(type): resolve TypeScript reference problem https://github.com/microsoft/TypeScript/issues/47663 — committed to donggua-nor/Blog by donggua-nor a year ago
- fix hub typechecking also setup paths and references in hub Ran into a strange issue when node_modules are symlinked: https://github.com/microsoft/TypeScript/issues/47663 Applied the workaround in ... — committed to deodad/hub by deodad a year ago
- fix hub typechecking also setup paths and references in hub Ran into a strange issue when node_modules are symlinked: https://github.com/microsoft/TypeScript/issues/47663 Applied the workaround in ... — committed to deodad/hub by deodad a year ago
- add workaround for issue microsoft/TypeScript#47663 — committed to zvictor/brainyduck by zvictor a year ago
- fix: TS build needs explicit typings/references https://github.com/microsoft/TypeScript/issues/47663#issuecomment-1519138189 The inferred type of 'createGenerator' cannot be named without a referen... — committed to chakra-ui/panda by astahmer a year ago
- dev: add build-dts scripts rm global tsbuildinfo cache as it causes stale issues ci: update build step with build-dts chore: rebase fixes + rm --dts flag & build-fast script fix: TS build needs explic... — committed to chakra-ui/panda by astahmer a year ago
- dev: add build-dts scripts rm global tsbuildinfo cache as it causes stale issues ci: update build step with build-dts chore: rebase fixes + rm --dts flag & build-fast script fix: TS build needs explic... — committed to chakra-ui/panda by astahmer a year ago
- dev: add build-dts scripts rm global tsbuildinfo cache as it causes stale issues ci: update build step with build-dts chore: rebase fixes + rm --dts flag & build-fast script fix: TS build needs explic... — committed to chakra-ui/panda by astahmer a year ago
- fix: enable isolated mode and use workaround for related typescript bug https://github.com/microsoft/TypeScript/issues/47663 — committed to payloadcms/payload by AlessioGr a year ago
- [react-web] Add hack for exposing PlasmicImg in generated code If you use codegen, and you use `declaration: true` in your tsconfig, and you have an image, you will see this error on this line of cod... — committed to plasmicapp/plasmic by chungwu 10 months ago
- chore(integration): Rename error to errors and fix "The inferred type of X cannot be named without a reference to Y" TS issue: https://github.com/microsoft/TypeScript/issues/47663 — committed to clerk/javascript by nikosdouvlis 7 months ago
- chore(integration): Rename error to errors and fix "The inferred type of X cannot be named without a reference to Y" TS issue: https://github.com/microsoft/TypeScript/issues/47663 — committed to clerk/javascript by nikosdouvlis 7 months ago
- chore(integration): Rename error to errors and fix "The inferred type of X cannot be named without a reference to Y" TS issue: https://github.com/microsoft/TypeScript/issues/47663 — committed to clerk/javascript by nikosdouvlis 7 months ago
- chore(*): Improve @clerk/clerk-react DX (#2328) * chore(clerk-react): Restrcture errors to separate module /errors module * chore(clerk-react): Move errorThrower.ts to /errors path * chore(clerk-re... — committed to clerk/javascript by dimkl 7 months ago
- feat: Implement Chapter 8 (Statements and State) (#16) See [Statements and State](https://craftinginterpreters.com/statements-and-state.html). No significant departures from the book. One minor d... — committed to danvk/gravlax by danvk 5 months ago
- feat: Fixes pnpm Monorepo Issue with Types (#137) # Description When installing the package in a pnpm monorepo, because of how the dependencies are managed, the imported configuration and analyti... — committed to colbyfayock/cloudinary-util by colbyfayock 5 months ago
- chore(release): 4.2.0 [skip ci] # [@cloudinary-util/url-loader-v4.2.0](https://github.com/colbyfayock/cloudinary-util/compare/@cloudinary-util/url-loader-v4.1.2...@cloudinary-util/url-loader-v4.2.0) ... — committed to colbyfayock/cloudinary-util by semantic-release-bot 5 months ago
- fix: :bug: update `tsconfig.json` - https://github.com/microsoft/TypeScript/issues/47663#issuecomment-1519138189 — committed to anyesu/taro-demo by anyesu 5 months ago
We at @hokify migrated a monorepo (~170 packages) based on npm workspaces to pnpm workspaces, and we had this error message a couple of times.
I want to share some insights we gained while resolving them - hope it helps others!
The problem
I created a minimal repository showing the error https://github.com/pkerschbaum/typescript-issue-pnpm-workspaces-this-is-likely-not-portable.
The package, just called
express-app
, has one dependency,express
.It takes only three lines to get the error:
Seems like there must be some prerequisites fulfilled to get this error:
"declaration": true
in tsconfig.json, or something like"composite": true
which also enables"declaration"
)While compiling, for every
.ts
source file, tsc has to create the corresponding declaration file.d.ts
. But in declaration files, type inference can technically not work; there are only types, no function bodies or assignments etc. - so where should a type even get inferred from?Consequently, when tsc compiles the source code and wants to output the
.d.ts
declaration files, then it must explicitly type the variables and functions. It must fill in the “holes” we leave when relying on type inference, so to say.For the code above, tsc wants to create the following declaration file:
This is because how
express
is typed:But here’s the thing:
express-serve-static-core
is not a dependency ofexpress-app
. Onlyexpress
is. So any package consuming that declaration file ofexpress-app
might not haveexpress-serve-static-core
installed.Hence the error
This is likely not portable
.Workarounds
(the repository https://github.com/pkerschbaum/typescript-issue-pnpm-workspaces-this-is-likely-not-portable has a branch for each of these workarounds)
1. Disable declaration emit of
express-app
(GitHub compare)Just set
"declaration": false
in tsconfig.json. Without declaration emit, tsc does not have to replace type inference by explicit types.Is of course only an option if the package is not consumed by any other TS package.
2. Explicitly type the variable/function (GitHub compare)
tsc will keep that explicit type in the declaration file:
Now the code only imports
express
, which is a dependency ofexpress-app
- thus it is valid and portable.3. Within the types of the library, export the interface/type which is required in your codebase
3.1 Re-export the interface in the types of the dependency. (GitHub compare)
When we change the types of
express
like this:…the code compiles!
This is because now, tsc can emit a valid declaration file:
But I think
Express
must be aninterface
and not atype
for this to work, see also my comment below.You can use pnpm patch to modify the code of dependencies.
3.2 Introduce an “intermediary interface” in the types of the dependency (GitHub compare)
If workaround 3.1 does not work because
Express
is a type (and not an interface), you can introduce an “intermediary interface” in the types of the dependency like this:This fixes the problem in a similar way like workaround 3.1 - the declaration then is:
4. Add the missing transitive dependency to the direct dependencies (GitHub compare)
We can fix compilation of
express-app
by addingexpress-serve-static-core
to the dependencies.Then, tsc can emit the declaration file and any package installing
express-app
will also getexpress-serve-static-core
.Drawback is of course that now the implementation details of
express
leak into ourexpress-app
.5. (⚠️ problematic) Switch from “isolated mode” to “hoisted mode” (GitHub compare)
In pnpm you can configure the option
node-linker=hoisted
. This will putexpress-serve-static-core
to the root of node_modules, thus tsc will emit the declaration file…because it thinks this dependency is available for sure.
But that might not be the case; imagine you publish
express-app
to the npm registry and someone installs it in a project using isolated mode - thenexpress-serve-static-core
is not present and it could introduce TypeScript errors on their side!6. (⚠️ problematic) Add the transitive dependency as path alias, and import it explicitly (GitHub compare)
Add this to tsconfig.json:
…and an import statement to the TS source file:
The import statement will put
express-serve-static-core
into the tsc compilation process, and thanks to the path alias it finds it.But this suffers from the same problem as the previous workaround - the declaration file:
…could be problematic for package consumers.
7. (⚠️ problematic) Enable
"preserveSymlinks"
in tsconfig.json (GitHub compare)tsc emits a declaration file which is inherently broken:
8. (⚠️ problematic) Use
declare module
to silent the error (GitHub compare)Add a file
global.d.ts
and add:This silences the error, however the emitted declaration is broken as it is in workaround <span>#</span>7:
I have a repro + a workaround/solution here
https://github.com/quadristan/ts-indirect-type-reference-bug
tl-dr:
same problem
This bug occurs pretty readily when using pnpm since the node_modules directory layout is different under pnpm than npm/yarn. Any npm package whose types reference another npm package’s type will generate the error
I’ve made a minimal reproduction here: https://github.com/mrmeku/portable_types_repro
What’s worse is that neither
// @ts-ignore
nor// @ts-expect-error
will allow us to ignore the incorrect error. This is a pretty gnarly bug.@RyanCavanaugh can a typescript team member look into this?
.pnpm
folder introducing anothernode_modules
in the path, triggering the warning, workaround withSorry, you’re right. I’ve misconfused this with yarn.
Several years later, the problem still persists
could you point me at the code responsible for that? I’m a core contributor to PNPM and this is the first time I’m hearing of it. not to say that I disagree with you or that it isn’t true, I’m just unaware of that.
is there any expected timeline for a fix for this problem?
turning the feature off is not fixing the issue, its just ignoring it and disabling functionality
@quadristan
You saved my life! I added:
This is definitely a super-nasty TypeScript bug. One of the worst I’ve encountered because it can’t be ignored and, in this case, took me hours to debug and find this solution.
same problem when using pnpm monorepo
And because I didn’t see it listed here. I had this same problem and couldn’t get the “import type {} from …” trick to work, but adding
preserveSymlinks: true
to my tsconfig compiler options completely fixed my problem. See this issue for more comments. Probably relevant, but my issue was with a pnpm monorepo.I’ve been deep-diving the issues related to this error and symlinks and pnpm specifically. Since 2019 it appears that this regression is reintroduced at least twice for each major version. That would suggest that tests are not sufficient for the case, nor to catch the regression.
same for me,
"typescript": "^5.3.3"
and pnpm 8.11.0Hi, unfortunately we have exactly the problem with dynamic types (through Prisma ORM) in the context of monorepo workspaces and PNPM. Please provide a fix for this.
Basically there are 3 issues playing a role:
*
pattern, only fully written/qualified entries reverse map properly: https://github.com/effect-ts-app/libs/blob/12a04db846d6cf5a535c811e7c60f0099e750602/patches/typescript%405.0.0-tsplus.20230113.patch#L10pnpm specific:
.pnpm
inside nodemodules can cause havoc with @types https://github.com/effect-ts-app/libs/blob/12a04db846d6cf5a535c811e7c60f0099e750602/patches/typescript%405.0.0-tsplus.20230113.patch#L20 I’m not suggesting this as a fix, but as a workaround it helped us.If no one can run with this, I hope to get some time to look at a clean patch and error report
Nice job! This is by far the best practice.👍
Same here for Version 5.3.3
Guess we should make a PR
@ivancuric I could fix your issue with workaround #<span></span>3 (“intermediary interface”), see https://github.com/pkerschbaum/repro-pnpm-types/commit/d3cd550990301959d058a3df65531c9a57d25146.
I forgot to mention one thing for workaround #<span></span>3: it must be an
interface
, not atype
.In the repo you provided, the broken code is:
It stays broken when we do this:
But it suddenly works when we do this:
That’s of course very weird and suggests that there is a bug in TypeScript. I think in its inner workings, tsc “optimizes away” simple type aliases. Both case #<span></span>1 and #<span></span>2 can be simplified to just
typeof exportedApi
, which tsc tries to put into the types of the packageimagecapture-main
. But this leads - for valid reasons - to theThis is likely not portable
error. Case #<span></span>3 seems to be not simple enough so tsc keeps theRemoteObj
type around, solving the error.Note that this is just my reasoning based on the observed behavior.
It’s really annoying that even with correct exports, this seems to be not working for
TS + pnpm + moduleResolution: 'NodeNext'
. Will this be fixed in TS?use type casting it is always solved in that way
The project I was working on extended a config that had
"declaration": true
, which was causing this.@takahashi-shotaro how did the wild card exports look?
I noticed that wildcards are evaluated only one way, but typescript needs to map two ways; the first mapping is when you try to import from x, But it also does a check if it can find an export entry based on the full file name. Typescript does not implement support for this reverse mapping check with wild cards, only statically defined entries.
which then causes the error, perhaps you run into this.
here https://github.com/microsoft/TypeScript/blob/84d8429fb623e0e89c1b59fe65d105eda094245f/src/compiler/moduleSpecifiers.ts#L863 is no matching mode specified, so it only supports the default: Exact
@pkerschbaum Thanks a ton for the in-depth solution.
I’d like to add in another solution on-top of the
It seems like I was able to accomplish the same thing by just re-exporting the inferred type from the intermediate, rather than having to create a whole new interface and exporting that. e.g.
@ivancuric This solution also works for your problem, where re-exporting the missing inferred type works rather than having to create a new interface
@ggascoigne - This got rid of the error but broke inference in my Redux store. Fwiw, I’m also encountering this issue in a monorepo (turborepo) + pnpm
same problem
I have managed to make the error go away by making a TypeScript Reference Type at the top of the file
In my case I was was importing
useI18n
function and spreading an object in it’s parameter object likeuseI18n({ ...someObj })
which caused this
The inferred type of useI18n cannot be named without a reference to .pnpm/@intlify+core-base@9.9.0/node_modules/@intlify/core-base . This is likely not portable. A type annotation is necessary.
✅ Fixed it by doing this
At the top of the file which used
useI18n
I’ve added the TS reference type like soSo to fix it, basically check the problematic package name ( in my case it was
@intlify/core-base
) and add it as a TypeScript Reference Type like in the example aboveThe fact that intersecting a type with an interface would make it suddenly works like a miracle indeed suggests something interesting. I’m not sure if @RyanCavanaugh @DanielRosenwasser has seen this hint, but if you haven’t, please prioritize.
In my case the error looks like this
The type definition wasn’t exported from root of the package but it was from
/lib/types
.So instead of just importing the package:
I had to specify the path which the type definition was exported:
@renke i have a repro where everything has the same version here : https://github.com/quadristan/ts-indirect-type-reference-bug
Same problem when building a react library alongside
styled-components
withtsup
Do we have any data around which of these workarounds are most reliable?
I’m experiencing the same issue with pnpm + Vue 3 + Pinia, using TanStack Query in a
defineStore
call, and so far, I haven’t found a workaround that’s worked yet. It could be that I’m importing the wrong types or using the wrong paths in said workaround, but alas. This also happened briefly with Vue Use’suseFetch
hook in the same store, and unfortunately I don’t remember how I resolved it previously. It wasn’t until I swapped it foruseQuery
that I got the error again.Started happening all of a sudden as well with no explanation like others have experienced in this issue (TS 5.3.3, pnpm 8.14)
Same here with typescript 5.3.3 and pnpm 8.14.0
Same here, just started seeing it all of a sudden. strange
Maybe you can try like this, post written in Chinese, I don’t guarantee it can solve your problem. https://juejin.cn/post/7282606413842415675
It’s a monorepo where the main app uses next.js, and the library module is pulled in using next.js’s experimental transpilePackages support. And it was working fine with this setup until I added a library that had previously only been used in that library to the main app. Now when code in the library is compiled in the app it gets a conflict.
The specific library is tss-react, it’s installed in two places:
eventually these resolve to identical hard linked files, though all of the directories along the way are unique.
And then it fails to compile with:
So, is this a pnpm bug? Well probably not really, but is it caused by pnpm, yes, it really is. And you can see from the error, the import trick isn’t working in this situation. the preserveSymlinks trick didn’t help on this one either, it just moved the error around.
The reason you see a history of this “regressing” at each version is that pnpm patches TypeScript when you install it, so every time TS updates, there’s a few days where it appears to not work because pnpm hasn’t updated their patching code yet.
This didn’t work for my
Nx
monorepo withpnpm
because in the workspace, peer dependencies were installed inside the library folder duplicating the package and causing the error. I opted to disable the peerdeps installation with:and reviewed the peer dependencies warnings to confirm that they were installed, and added the ones missing: then I confirmed that everything ran as expected.
I am having this issue as well, on v5.3.3.
While removing
"declaration": true
makes the issue go away, I am writing a module that I plan to publish on NPM, so disabling the output of declaration files is quite simply not an option, seeing as the module will not function without those files. Quite similar to how TypeScript complains if you don’t have the@types/X
package installed for a legacy package (i.e. one that doesn’t include its own typings).In a simple class that wraps around the client created by
node-redis
:Makes it impossible to use Redis in the following way, where you can have tons of custom scripts/commands that are very difficult if impossible to correctly reflect using the package’s included types, and not using
typeof client
at runtime as suggested here:This code alone generates 137 TS compiler errors, all in the format shown in the first screenshot. It’s very unfortunate that this has been an ongoing issue for so long. It feels like I have hit a brick wall, as this one error essentially renders TS unusable. Every workaround that compiles involves stripping varying levels of contextual data from the type (such as explicitly setting the type of client to
any
), which undermines the entire point of using TypeScript in the first place.I’ve been experiencing this same issue
The inferred type of storyFactory cannot be named without a reference to .pnpm/@intlify+core-base@9.8.0/node_modules/@intlify/core-base . This is likely not portable. A type annotation is necessary.
and the way I’ve worked around it was to add this, although it would be nice if this issue gets fixed since it has been present for years
👇
FYI I posted a comment with 7 workarounds a while ago (link), and all of them apply also to the latest TypeScript version (5.3.3).
I have a pnpm monorepo with a package and an app using that package:
The type error that prevents building looks like this in the backend-adapters package:
where
setupRestAPIWorker
is just:The Typescript configuration for this package comes from the root of the monorepo. There is a
tsconfig.base.json
in the root of the monorepo that is shared by all the apps and packages:There’s also a
tsconfig.lib.json
in the root of the monorepo intended for use by packages specifically:So our package backend-adapters uses the lib config above like so:
Based on how config inheritance works, this means that
moduleResolution
for this package is set toNode16
.So at this point, I’ve tried all the solutions presented in @pkerschbaum 's comment way above and I found that none of them worked. What actually worked was changing the
moduleResolution
in the packagetsconfig.json
back toNode
. This option is clearly deprecated so this doesn’t feel ideal. 😢Tooling versions:
4.9.5
1.3.2
18.15.0
Edit 1:
Further debugging: I ran
tsc --traceResolution
in the package withmoduleResolution: Node16
and got thisI ran
tsc --traceResolution
in the package withmoduleResolution: Node
and got this:Looks like it resolved successfully both times so not exactly sure what’s going on here.
@robin-pham’s fix worked for me too. My halfass writeup:
Error:
pnpm link ../B
foodtruck-js
{ FreeTacos }
fromB/src/freetacos.ts
FreeTacos
uses a type inferred fromfoodtruck-js
FreeTacos
, but A does not importfoodtruck-js
The inferred type of 'FreeTacos' cannot be named without a reference to 'B/node_modules/foodtruck-js'. This is likely not portable. A type annotation is necessary.ts(2742)
Fix:
export type * from 'foodtruck-js'
in repo B’s index file (need to dig through which specific types are requiring the issue).foodtruck-js
as a package dependency in A.Us too, same tools!
@robin-pham you are right! I have split workaround 3 in two subparts and your suggestion is 3.1, the other 3.2 😃
I could look into it if you provide a minimal reproduction repository
same problem with using pnpm but not monorepo. “preserveSymlinks”: true also worked.
Keep looking for the real problem and the better solution
sure thing. feel free to DM me info on twitter as well.
So, aside from finding a solution to this problem, is my assumption correct that having multiple packages with typings that have the same version should not cause any problems?
I’d also appreciate any hints on where to look at the source code to solve this problem.