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

Most upvoted comments

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:

import * as express from "express";
const app = express();
//     ^ The inferred type of 'app' cannot be named without a reference to '.pnpm/@types+express-serve-static-core@4.17.33/node_modules/@types/express-serve-static-core'. This is likely not portable. A type annotation is necessary.ts(2742)
export { app };

Seems like there must be some prerequisites fulfilled to get this error:

  • “isolated mode” is used to build the node_modules structure (pnpm uses isolated mode by default)
  • the TS package is configured to emit declaration files (explicitly by "declaration": true in tsconfig.json, or something like "composite": true which also enables "declaration")
  • in the TS source, type inference for a variable or function return type is used
  • and that variable/function gets exported

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:

declare const app: import("express-serve-static-core").Express;
export { app };

This is because how express is typed:

import * as core from 'express-serve-static-core';
declare function e(): core.Express;

But here’s the thing: express-serve-static-core is not a dependency of express-app. Only express is. So any package consuming that declaration file of express-app might not have express-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)

import * as express from "express";
- const app = express();
+ const app: ReturnType<typeof express> = express();
export { app };

tsc will keep that explicit type in the declaration file:

import * as express from "express";
declare const app: ReturnType<typeof express>;
export { app };

Now the code only imports express, which is a dependency of express-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:

import * as core from 'express-serve-static-core';
+ export { Express } from 'express-serve-static-core';

…the code compiles!

This is because now, tsc can emit a valid declaration file:

import * as express from "express";
declare const app: express.Express;
export { app };

But I think Express must be an interface and not a type 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:

import * as core from 'express-serve-static-core';
+ export interface MyExpress extends core.Express {}
- declare function e(): core.Express;
+ declare function e(): MyExpress;

This fixes the problem in a similar way like workaround 3.1 - the declaration then is:

import * as express from "express";
declare const app: express.MyExpress;
export { app };

4. Add the missing transitive dependency to the direct dependencies (GitHub compare)

We can fix compilation of express-app by adding express-serve-static-core to the dependencies.
Then, tsc can emit the declaration file and any package installing express-app will also get express-serve-static-core.

Drawback is of course that now the implementation details of express leak into our express-app.

5. (⚠️ problematic) Switch from “isolated mode” to “hoisted mode” (GitHub compare)

In pnpm you can configure the option node-linker=hoisted. This will put express-serve-static-core to the root of node_modules, thus tsc will emit the declaration file

import * as core from 'express-serve-static-core';
declare function e(): core.Express;

…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 - then express-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:

{
  "compilerOptions": {
    "paths": {
      "express-serve-static-core": [
        "./node_modules/.pnpm/@types+express-serve-static-core@4.17.33/node_modules/@types/express-serve-static-core"
      ]
    }
  }
}

…and an import statement to the TS source file:

import * as express from "express";
+ import "express-serve-static-core";
const app = express();
export { app };

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:

import * as core from 'express-serve-static-core';
declare function e(): core.Express;

…could be problematic for package consumers.

7. (⚠️ problematic) Enable "preserveSymlinks" in tsconfig.json (GitHub compare)

tsc emits a declaration file which is inherently broken:

declare const app: core.Express; // TS error here: Cannot find namespace 'core'
export { app };

8. (⚠️ problematic) Use declare module to silent the error (GitHub compare)

Add a file global.d.ts and add:

declare module "express-serve-static-core" {}

This silences the error, however the emitted declaration is broken as it is in workaround <span>#</span>7:

declare const app: core.Express; // TS error here: Cannot find namespace 'core'
export { app };

I have a repro + a workaround/solution here

https://github.com/quadristan/ts-indirect-type-reference-bug

tl-dr:


import type {} from "Y"; // or whatever Y really refers to

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?

-  const nodeModulesDirectoryName = moduleSpecifier.substring(parts.topLevelPackageNameIndex + 1);
+  const nodeModulesDirectoryName = moduleSpecifier.substring(parts.topLevelPackageNameIndex + 1).replace(/\.pnpm\/[^\/]+\/node_modules\//, "");```

Sorry, you’re right. I’ve misconfused this with yarn.

Several years later, the problem still persists

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.

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.

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?

This error is because declaration: true in tsconfig.json and declaration is true when composite: true. 🚀

https://www.typescriptlang.org/tsconfig#declaration

turning the feature off is not fixing the issue, its just ignoring it and disabling functionality

@quadristan

You saved my life! I added:

import type {} from 'react'

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.0 image

Hi, 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:

pnpm specific:

If no one can run with this, I hope to get some time to look at a clean patch and error report

I have a repro + a workaround/solution here

https://github.com/quadristan/ts-indirect-type-reference-bug

tl-dr:

import type {} from "Y"; // or whatever Y really refers to

Nice job! This is by far the best practice.👍

Same here for Version 5.3.3

@patroza After applying your patch I can now export with wildcards, thanks.

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 a type.
In the repo you provided, the broken code is:

// case #1, just reexport
export type RemoteObj = typeof exportedApi;

It stays broken when we do this:

// case #2, intersection type with empty object
export type RemoteObj = typeof exportedApi & {};

But it suddenly works when we do this:

// case #3, intersection type with interface
interface MyBlah {}
export type RemoteObj = typeof exportedApi & MyBlah;

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 package imagecapture-main. But this leads - for valid reasons - to the This is likely not portable error. Case #<span></span>3 seems to be not simple enough so tsc keeps the RemoteObj 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

  1. Introduce an “intermediary interface” in the types of the dependency

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.

diff --git a/index.d.ts b/index.d.ts
index 53dc74d77277c7fa4fd459caa7ed261bf3a0ea02..71532cbd99dca6bcf102c000345156d39950a5b0 100755
--- a/index.d.ts
+++ b/index.d.ts
@@ -21,6 +21,8 @@ import * as serveStatic from 'serve-static';
 import * as core from 'express-serve-static-core';
 import * as qs from 'qs';

+export { Express } from 'express-serve-static-core';
+
 /**
  * Creates an Express application. The express() function is a top-level function exported by the express module.
  */

@ivancuric This solution also works for your problem, where re-exporting the missing inferred type works rather than having to create a new interface

+export type { ImageCaptureBindings } from "imagecapture-wasm";
export type RemoteObj = typeof exportedApi;

@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 like useI18n({ ...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 so

/// <reference types="@intlify/core-base" />

So 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 above

@ivancuric I could fix your issue with workaround #3 (“intermediary interface”), see https://github.com/pkerschbaum/repro-pnpm-types/commit/d3cd550990301959d058a3df65531c9a57d25146.

I forgot to mention one thing for workaround #3: it must be an interface, not a type. In the repo you provided, the broken code is:

// case #1, just reexport
export type RemoteObj = typeof exportedApi;

It stays broken when we do this:

// case #2, intersection type with empty object
export type RemoteObj = typeof exportedApi & {};

But it suddenly works when we do this:

// case #3, intersection type with interface
interface MyBlah {}
export type RemoteObj = typeof exportedApi & MyBlah;

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 #1 and #2 can be simplified to just typeof exportedApi, which tsc tries to put into the types of the package imagecapture-main. But this leads - for valid reasons - to the This is likely not portable error. Case #3 seems to be not simple enough so tsc keeps the RemoteObj type around, solving the error.

Note that this is just my reasoning based on the observed behavior.

The 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 inferred type of 'Foo' cannot be named without a reference to '.pnpm/@morphic-ts+model-algebras@3.0.0_.../node_modules/@morphic-ts/model-algebras/lib/types'. This is likely not portable. A type annotation is necessary

The type definition wasn’t exported from root of the package but it was from/lib/types.

So instead of just importing the package:

import type {} from '@morphic-ts/model-algebras'

I had to specify the path which the type definition was exported:

import type {} from '@morphic-ts/model-algebras/lib/types'

@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 with tsup

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).

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’s useFetch hook in the same store, and unfortunately I don’t remember how I resolved it previously. It wasn’t until I swapped it for useQuery that I got the error again.

image

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

I’m on TS 5.2.2 & pnpm, suddenly started happening

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:

$ ls -l apps/acnw/node_modules
...
lrwxr-xr-x   1 ggp   93 Dec 14 16:45 tss-react -> ../../../node_modules/.pnpm/tss-react@4.4.4_7gkcoq2nf4xufkduddb7kah6jm/node_modules/tss-react
$ ls -l packages/ui/node_modules
...
lrwxr-xr-x   1 ggp   93 Dec 11 15:33 tss-react -> ../../../node_modules/.pnpm/tss-react@4.4.4_hp5f5nkljdiwilp4rgxyefcplu/node_modules/tss-react
$ls -ld node_modules/.pnpm/tss-react*
drwxr-xr-x  3 ggp  staff  96 Dec 14 16:45 node_modules/.pnpm/tss-react@4.4.4_7gkcoq2nf4xufkduddb7kah6jm
drwxr-xr-x  3 ggp  staff  96 Dec 11 15:33 node_modules/.pnpm/tss-react@4.4.4_hp5f5nkljdiwilp4rgxyefcplu

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:

../../packages/ui/components/Card/Card.tsx:5:14
Type error: The inferred type of 'useStyles' cannot be named without a reference to '../../../../apps/acnw/node_modules/tss-react/types'. This is likely not portable. A type annotation is necessary.

  3 | import {} from 'tss-react/types'
  4 |
> 5 | export const useStyles = makeStyles()({
    |              ^

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.

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.

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.

import type {} from "Y";

This didn’t work for my Nx monorepo with pnpm 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:

.npmrc
auto-install-peers=false

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:

chrome_sBvPyfjEQ9

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:

webstorm64_YKr2KZhL82

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

👇

declare module '@intlify/core-base' {}

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:

pnpm-monorepo
  apps
    react-frontend (uses "backend-adapters". has a dependency on the "msw" package)
  packages
    backend-adapters (has a dependency on the "msw" package)
      adapters
      schemas
      mocks

The type error that prevents building looks like this in the backend-adapters package:

The inferred type of setupRestAPIWorker cannot be named without a reference to ../../node_modules/msw/lib/glossary-de6278a9 . This is likely not portable. A type annotation is necessary.

where setupRestAPIWorker is just:

import { restHandlers } from "../mocks/handlers";
import { setupWorker } from "msw";

/**
 * Mock Service worker for all REST API adapters in the domain package
 * @returns a MSW instance
 */
const setupRestAPIWorker = () =>
  setupWorker(...Object.values(restHandlers).flat()); // red squiggly line in VSCode shows up in the const here thanks to Typescript

export { setupRestAPIWorker };

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:

{
  "compilerOptions": {
    "moduleResolution": "node16",
    "target": "ES2022",
    "module": "ES2022",
    "lib": ["ES2022", "DOM", "DOM.Iterable"],
    "allowJs": true,
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "noImplicitReturns": true,
    "allowUnreachableCode": false,
    "allowUnusedLabels": false,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  }
}

There’s also a tsconfig.lib.json in the root of the monorepo intended for use by packages specifically:

{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "composite": true,
    "declaration": true,
    "declarationMap": true,
    "noEmitOnError": true,
    "emitDeclarationOnly": true
  }
}

So our package backend-adapters uses the lib config above like so:

{
  "extends": "../../tsconfig.lib.json",
  "compilerOptions": {
    "strict": true,
    "sourceMap": true,
    "declarationDir": "lib/types",
    "resolveJsonModule": true,
    "noEmitOnError": false,
    "outDir": "lib",
    "isolatedModules": true,
    "useDefineForClassFields": true
  },
  "include": ["src/**/*", "package.json"]
}

Based on how config inheritance works, this means that moduleResolution for this package is set to Node16.

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 package tsconfig.json back to Node. This option is clearly deprecated so this doesn’t feel ideal. 😢

Tooling versions:

  • Typescript 4.9.5
  • MSW 1.3.2
  • Node 18.15.0

Edit 1:

Further debugging: I ran tsc --traceResolution in the package with moduleResolution: Node16 and got this

======== Module name 'msw' was successfully resolved to '/[obfuscated-path]/pnpm-monorepo/node_modules/.pnpm/msw@1.3.2_typescript@4.9.5/node_modules/msw/lib/index.d.ts' with Package ID 'msw/lib/index.d.ts@1.3.2'. ========
File '/[obfuscated-path]/pnpm-monorepo/packages/backend-adapters/src/package.json' does not exist according to earlier cached lookups.
File '/[obfuscated-path]/pnpm-monorepo/packages/backend-adapters/package.json' exists according to earlier cached lookups.

I ran tsc --traceResolution in the package with moduleResolution: Node and got this:

======== Module name 'msw' was successfully resolved to '/[obfuscated-path]/pnpm-monorepo/node_modules/.pnpm/msw@1.3.2_typescript@4.9.5/node_modules/msw/lib/index.d.ts' with Package ID 'msw/lib/index.d.ts@1.3.2'. ========

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:

  • using pnpm and TS 4.9.4
  • A and B are in separate monorepos
  • in A: pnpm link ../B
  • B uses package dependency foodtruck-js
  • B exports { FreeTacos } from B/src/freetacos.ts
  • FreeTacos uses a type inferred from foodtruck-js
  • A imports FreeTacos, but A does not import foodtruck-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:

  • Add an export type * from 'foodtruck-js' in repo B’s index file (need to dig through which specific types are requiring the issue).
  • I did not need to add foodtruck-js as a package dependency in A.

Hi, 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.

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

因为我没有看到它在这里列出。我遇到了同样的问题,无法从…获得“导入类型 {}”技巧工作,但添加到我的 tsconfig 编译器选项完全解决了我的问题。有关更多评论,请参阅此问题。可能相关,但我的问题是 pnpm 单存储库。preserveSymlinks: true

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.