TypeScript
TypeScript copied to clipboard
"The inferred type of X cannot be named without a reference to Y" (TS2742) still happens, when working with npm link to link packages manually
🔎 Search Terms
is:issue is:open 2742
🕗 Version & Regression Information
This seems to not be a regression bug
⏯ Playground Link
https://github.com/Teascade/typescript-error-demonstration
💻 Code
// In the example provided
// https://github.com/Teascade/typescript-error-demonstration
import { extended } from '@privateprefix/lib';
// src/index.ts(4,14): error TS2742: The inferred type of 'a' cannot be named without a reference to '@privateprefix/lib/node_modules/joi'. This is likely not portable. A type annotation is necessary.
export const a = extended.object().keys();
Replacing this with
// Joi is declared, but never used ts(6133)
import { type Joi, extended } from '@privateprefix/lib';
// This works now, though
export const a = extended.object().keys();
🙁 Actual behavior
Produces src/index.ts(4,14): error TS2742: The inferred type of 'a' cannot be named without a reference to '@privateprefix/lib/node_modules/joi'. This is likely not portable. A type annotation is necessary.
🙂 Expected behavior
No error is to be expected
Additional information about the issue
In https://github.com/microsoft/TypeScript/issues/42873#issuecomment-2066874644 it was mentioned, that this issue would now be resolved in TypeScript beta 5.5.0, but it seems to still be broken in this specific scenario
I've made a minimal repository to reroduce this issue in https://github.com/Teascade/typescript-error-demonstration
The GitHub repository has a github action in which the issue is reproduced: https://github.com/Teascade/typescript-error-demonstration/actions/runs/9568149578/job/26377636108
I did not go into vivid detail into what could possibly be causing this issue, when it has supposedly been fixed in the general case for pnpm, because I frankly do not know what it could be, but the repository is not very big and contains everything needed to reproduce the error.
I'm suspecting this instance has something to do with npm link, as when the library is simply installed via tarball, it works just fine
It doesn't really have anything to do with npm link - it's just that we don't see the Joi types reexported in @privateprefix/lib as an autogeneratable way to reference joi's innards, hence why it works when you explicitly import the alias to Joi. (The tarball install works because npm hoists the install to the top level, rather than doing the strict dependency nesting the link does.) We do do a little bit of looking for reexports, but generally we look for complete reexports, where one module is another module via export = - a nested reexport like this, where you import a default and reexport it as a named member I just don't think is an alias we current traverse through while looking for reachable ways to name the module. So this is probably fixable, but the logic's going to be a bit weird, since we'll be looking for module symbol aliases at... basically every symbol name everywhere (rather than just reachable filenames).
Thanks for the answer @weswigham, as an aspiring Compiler Technician myself I actually entirely understand, and was honestly a little surprised as a similar problem causing this error had been solved via #42873, so it gave me hope that maybe this could be solved too, somehow.
This problem occurs to me at work, and while I obviously can't disclose the details, the situation (and the problem) is pretty much identical. The part that frustrates me the most, is that we used to only use Javascript + JSDoc and simply TypeScript-checked all of our files. Now that we are transitioning to full-typescript, this has become an issue, almost out of nowhere. It's befuddling, and frustrating.
I must try and check, if the problem persists in the minimal repository if the files were instead JS+JSDoc+autogenerated Typescript Declaration files, but I suspect the problem would not exist there.
This is especially frustrating again, because we have a lot of repositories, and using them via published npm-packages works just fine (ie. the tarball works), but manually linking the packages together during development, to make development easier, now breaks :/
I'm seeing a similar issue in a monorepo on 5.5 ("moduleResolution": "Node16") where a package re-exports io-ts.
error TS2742: The inferred type of 'Foo' cannot be named without a reference to '../../../node_modules/monorepo-package/transient-module.js'. This is likely not portable. A type annotation is necessary.
export const Foo = t.etc({
~~~
The module from which we import * as t itself imports a type from transient-module. I can workaround this with import "monorepo-package/transient-module" alongside Foo, but that's far from ideal.
If this isn't expected or it's unclear why it'd be happening I can try and come up with a small repro.
I must try and check, if the problem persists in the minimal repository if the files were instead JS+JSDoc+autogenerated Typescript Declaration files, but I suspect the problem would not exist there.
As I promised here, after a while I've made the necessary changes in jsdoc-branch of the original referenced project.
I also updated the expected typescript version to a newer 5.5.3. The problem still persists on main-branch with this new issue (as expected), but on the new jsdoc-branch, where the situation is to my understanding identical, except the source code is javascript, with typing-annotations using jsdoc. The produced declaration files I believe should be identical, though I admit I haven't checked.
My question really is, can you explain why this is? At work, I've for years wanted to move from javascript (+jsdoc) onto true typescript, because of multiple benefits that I see with using just typescript, but for some reason that I can't really explain, we've had issues like these emerge.. "out of nowhere"? With basically identical source code, and identical typescript-configuration files, just moving from javascript to typescript.
I thought the move would be easier.
Recently upgraded to 5.5.4 without any of these issues, when I installed 5.6.0-beta got a bunch of these. 300+ package pnpm monorepo. Don't have a reproduction case but just noting that this was not a problem in 5.5.4.
Can confirm this is still an issue when using NPM link. When the linked lib exports a value with a type depending on another third party lib, even if the project importing the linked lib has the (exact same version of the) third party lib as a dependency, TS will fail to recognize that.
// Error. Can't resolve types for node_modules/LinkedLib/ThirdParty
MyCode --> Lib (file://...) --> ThirdParty (v1.2.3)
--> ThirdParty (v1.2.3)
// This works just fine
MyCode --> Lib (v1.1.1) --> ThirdParty (v1.2.3)
--> ThirdParty (v1.2.3)
Seeing this as well with Bazel when setting up sandbox with symlinked node_modules. Only with 5.6.
It happens with some specific 3rd party packages like storybook.
import type { Meta } from "@storybook/react";
export const M: Meta = {};
export const M2 = M;
with error:
The inferred type of 'M2' cannot be named without a reference to
'<sandbox-path>/node_modules/storybook/core/types'.
This is likely not portable. A type annotation is necessary.ts(2742)
While I can solve it with export const M2: typeof M = M or : Meta I believe something broke in 5.6.
The same code works in a non-symlinked node_modules environment.
@elado Luckily all my issues for this were in application code, not package code, so I just turned off all the declaration* options in tsconfig and ignored the issue
I am also encountering this issue and wanted to share additional context that might help in diagnosing the problem.
I have created a minimal reproduction repository that demonstrates the issue:
https://github.com/skrtheboss/reproduce-inferred-type-error
Steps to reproduce:
-
Clone the repository.
-
Install dependencies:
pnpm install -
Run the command:
pnpm nx run test-lib:build -
Observe the following error during TypeScript compilation:
> nx run test-lib:build Compiling TypeScript files for project "test-lib"... libs/test-lib/src/index.ts:7:14 - error TS2742: The inferred type of 'BDTO' cannot be named without a reference to '.pnpm/@[email protected]_bx7ns4a6im6ljmadd2c7gy34li/node_modules/@nestjs/common'. This is likely not portable. A type annotation is necessary. 7 export class BDTO extends OmitType(ADTO, ['foo']) {} ~~~~
Workaround: Adding the following line to the imports resolves the issue:
import type {} from '@nestjs/common';
Let me know if further details or tweaks to the reproduction are needed. I'd appreciate any guidance or updates regarding a potential fix. Thanks!
Our fix for this relies on package.json files within the compilation folder to discover available dependencies not explicitly included via imports in the project. To avoid crawling the whole directory spine, we stop looking for package files at the project root. nx, however, seems to avoid using per-project package manifests, so we never find those deps, since they're only declared in a folder above each project, which means you're back to the old workaround: either annotate it yourself, like the error asks, or add an import "@nestjs/common"; to a file in the project to force us to discover the dep.
Our fix, still to this day, basically means that we write everything in JSDoc, because that works. Pure typescript does not work.
Although lately as of version 5.6.3 (as reported by #60214 and #59951) this problem has started to appear on JSDoc files as well, which is significantly worse than before.
We have something like 30 repositories and 2 people managing them all (yes I would change it if I had the power to) and I'm seriously considering simply freezing to some very old typescript version for the forseeable future, because it seems like this problem just keeps getting worse with each update.
The reason we don't freeze our typescript version is simply because I encounter typescript bugs maybe on a monthly basis, which are sometimes fixed quickly and sometimes not, and never having these bugs fixed has been historically worse than some breaking changes that sometimes appear.
Using explainFiles I got this:
Imported via "@org/util-types/stringTypes.js" from file '@org/libs/util-types/dist/helpers.d.ts' with packageId '@org/util-types/src/[email protected]'
And wondered: how does TSC even know about src? The package exports points to ./dist/*, so "@org/util-types/stringTypes.js" should point to dist/stringTypes.js
It turns out, TSC is reading the imported package's tsconfig! If I build util-types, then delete tsconfig.json, then building other packages that depend on it no longer show the cannot be named error.
I tried setting these two options but that did not change:
"disableSourceOfProjectReferenceRedirect": true,
"disableSolutionSearching": true,
Why is TSC ignoring the already-generated files and trying to read the source again? It seems that a DX improvement (i.e. pointing imports to the source) is leaking into the typechecking itself.
So, is there a solution now?
Today I was finally able to drop every workaround from my monorepo. In my case the workaround looked like this:
// eslint-disable-next-line import/no-unassigned-import -- Fix for TS2742
import type {} from "@my-org/my-package/whichever-file-ts-said-it-cannot-name.js";
It's hard to say what fixed it, but for the past few months I've been working towards reducing the custom config of my repo, and that included dropping all paths from tsconfig in favor of exports and imports in package.json, as well as using extensions for all imports.
So my guess is that TS has a hard time connecting the dots when paths is used. I still have a couple of paths but they're very specific to 3 files and not like @app/* anymore.
for the me issue was with trpc - same issue as yours
import { initTRPC } from '@trpc/server'
import { createExpressMiddleware } from '@trpc/server/adapters/express'
export const t = initTRPC.create()
export const trpcRouter = t.router({
// ...
})
export const expressAdapter = createExpressMiddleware({
router: trpcRouter,
})
expressAdapter produced the issue. The solution ✔ was to explicitly install @types/express and the bundler could finally realize what types it was working with
Interestingly, this issue only occurred to me through tsserver, when running tsc --build directly, the issue did not happen. I was migrating a path alias-based pnpm workspaces NX repository to use tsconfig references, which was mostly smooth sailing apart from this issue.
In the end, what turned out to be the culprit was a really wide path alias in the application tsconfig:
// Before
// ...
"compilerOptions": {
"paths": {
"@app/*": ["./*"]
}
},
// ...
// After
// ...
"compilerOptions": {
"paths": {
"@app/api/*": ["./api/*"],
"@app/client": ["./client/index.ts"],
"@app/client/*": ["./client/*"],
"@app/components/*": ["./components/*"],
"@app/constants/*": ["./constants/*"],
// ...
}
},
// ...
I can second the assumption that the issue can have something to do with path aliases from https://github.com/microsoft/TypeScript/issues/58914#issuecomment-2908734119