microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
98.26k stars 12.2k forks source link

"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 #47663

Closed renke closed 1 week ago

renke commented 2 years ago

Bug Report

๐Ÿ”Ž Search Terms

๐Ÿ•— 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.

pkerschbaum commented 12 months ago

I could look into it if you provide a minimal reproduction repository

ivancuric commented 12 months ago

I could look into it if you provide a minimal reproduction repository

Thanks.

Here it is in a semi-broken state: https://github.com/ivancuric/repro-pnpm-types

pnpm build will build all the packages.

One step can be fixed by uncommenting:

// import type {} from "imagecapture-wasm";
// import type {} from "imagecapture-worker";

Weirdly enough, the apps/example-solidjs package isn't complaining in this repo like the original one did:

The inferred type of 'workerRoot' cannot be named without a reference to '../../../packages/imagecapture-worker/node_modules/comlink/dist/umd/comlink'. This is likely not portable. A type annotation is necessary.ts(2742)

The inferred type of 'workerRoot' cannot be named without a reference to '../../../packages/imagecapture-worker/node_modules/imagecapture-wasm/types'. This is likely not portable. A type annotation is necessary.ts(2742)

I also noticed that what VScode's TS server shows isn't indicative of what the actual state is. It can show both false positives and negatives. Sometimes quitting helps when restarting the server or reloading the window fails.

pkerschbaum commented 12 months ago

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

nopeless commented 11 months ago

Throwing in my solution just in case someone else has the same problem

I had a symlinked package and that was causing the issue. Unlinking and relinking fixes the issue

robin-pham commented 11 months ago

@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;
pkerschbaum commented 11 months ago

@robin-pham you are right! I have split workaround 3 in two subparts and your suggestion is 3.1, the other 3.2 :)

silasdavis commented 11 months ago

@pkerschbaum thanks for the detailed write-up it certainly saved me some time.

I can confirm the re-export works. I am in a monorepo context with Yarn 3 and .yarnrc.yml:

nmHoistingLimits: workspaces

nmMode: hardlinks-local

nodeLinker: node-modules

Which gives similar results to pnpm isolation.

The crux of this seems is that the 'resolution' used when generating declaration files is different to the way node resolution resolves compiled files, so we have:

So any package consuming that declaration file of express-app might not have express-serve-static-core installed.

But we don't usually need to introduce a direct dependency in order to consume transitive dependencies, but apparently for type declarations we do *under the conditions enumerated here: https://github.com/microsoft/TypeScript/issues/47663#issuecomment-1519138189).

I'd be interested to understand the technical limitation here and how fundamental it is or otherwise to the way types are resolved.

Do types for a module need to be flattened into the declaration file at the root of the import? I can see how this would become bloated.

One thing I tried that did not work was to re-export the module from the direct dependency of the module that was complaining, but only re-exporting it from the consuming module that was failing to compile worked, as in:

A --depends on--> B

Compiling A gives:

The inferred type of 'Foo' cannot be named without a reference to 'B/node_modules/foo'. This is likely not portable. A type annotation is necessary

Re-exporting Foo from B does not work, re-exporting from A from the file where the error is emitted does.

alexanderniebuhr commented 11 months ago

@pkerschbaum thanks for your write-up.

I'm currently trying to fix: https://github.com/drizzle-team/drizzle-orm/issues/656 However it seems all workarounds do not work, and the suggested workarounds in the issue, seem bad. Can someone help to find the root cause?

takahashi-shotaro commented 11 months ago

When using "moduleResolution": "node16", if we use a library that has exports defined in package.json, it seems that we cannot import file unless the file is enumerated in exports (Note that wildcard export did not work for me).

  "exports": {
    ".": {
      "types": "./index.d.ts",
      "import": "./index.mjs",
      "require": "./index.cjs",
      "default": "./index.mjs"
    },
    "./additional-types": {
      "types": "./additional-types.d.ts"
    }
  }
patroza commented 11 months ago

@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

takahashi-shotaro commented 11 months ago

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

patroza commented 11 months ago

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

Guess we should make a PR

liqMats commented 9 months ago

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.

DavidVaness commented 9 months ago

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!

patroza commented 9 months ago

@RyanCavanaugh can a typescript team member look into this?

muziyan commented 9 months ago

I'm encountering the same issue while using @mui/material and @emotion/styled. Currently, I need to manually declare types to resolve it. to chinese

image

I have read some of the suggested solutions in the comments, but they haven't been helpful for me. I'd like to know if this issue will be fixed in the future.

alexanderniebuhr commented 9 months ago

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?

mattidupre commented 8 months ago

@robin-pham's fix worked for me too. My halfass writeup:

Error:

Fix:

cumt-robin commented 8 months ago

same problem when using pnpm monorepo

patroza commented 7 months ago

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

cumt-robin commented 7 months ago

Maybe you can try like this, post written in Chinese, I don't guarantee it can solve your problem. https://juejin.cn/post/7282606413842415675

ekr3peeK commented 7 months ago

@RyanCavanaugh The issue is happening to me on npm monorepos as well.

It seems to me, that typescript is not recognizing the outermost node_module folder as part of the project. Am I missing some tsconfig setting that should be applied when working in monorepos?

I am getting the following error:

The inferred type of 'initializeModules' cannot be named without a reference to '../../../../node_modules/@yellow/core/dist/Classes/Mustache'. This is likely not portable. A type annotation is necessary.ts(2742)

This is how my package.json file looks like:

{
    "name": "@ratestay/server",
    "version": "1.0.0",
    "scripts": {
        "build": "rm -Rf dist && tsc --project tsconfig.build.json --noEmit && BABEL_ENV=prod babel src --out-dir dist --copy-files --extensions '.ts,.js'",
        "lint": "eslint src/** && tsc --noEmit --project tsconfig.json",
        "typecheck": "tsc --project tsconfig.build.json --noEmit",
        "dev": "nodemon",
        "start": "node build/index.js"
    },
    "nodemonConfig": {
        "exec": "BABEL_ENV=dev DEV_ENV=true NODE_OPTIONS='--conditions=developement' babel-node -x .ts,.js --ignore '*\/node_modules\/*' src/index.ts",
        "ext": ".ts",
        "delay": "500",
        "watch": [
            "./src/*",
            "./../../../packages/*"
        ]
    },
    "devDependencies": {
        "@types/express": "^4.17.17",
        "@types/nodemailer": "^6.4.10",
        "@yellow-utils/babel": "^1.0.0",
        "@yellow-utils/eslint-config": "^1.0.0",
        "@yellow-utils/tsconfig": "^1.0.0",
        "nodemon": "^3.0.1",
        "type-fest": "^4.3.1",
        "typescript": "^5.2.2"
    },
    "dependencies": {
        "@yellow/backend": "*",
        "@yellow/core": "^1.1.6",
        "express": "^4.18.2",
        "lodash": "^4.17.21",
        "nodemailer": "^6.9.5",
        "sequelize": "^6.32.1"
    }
}

And this is my tsconfig.json file:

{
    "extends": "@yellow-utils/tsconfig/tsconfig.base.json",
    "compilerOptions": {
        "rootDir": "./src",
        "paths": {
            "@yellow/backend": ["./../../../packages/@yellow/backend/src/index.ts"],
            "@yellow/backend/sequelize": ["./../../../packages/@yellow/backend/src/exports/sequelize.ts"],
            "config": ["./src/config/config.local.ts", "./src/config/config.ts"]
        }
    },
    "references": [
        {"path": "./../../../packages/@yellow/backend/tsconfig.json"}
    ],
    "include": ["./src/**/*"],
    "exclude": ["node_modules/"]
}

If you say that this should work on npm monorepos, than maybe I am having some configuration problems, that can solve this.

For reference, I am including the extended config as well:


// @yellow-utils/tsconfig/tsconfig.base.json
{
    "$schema": "https://json.schemastore.org/tsconfig",
    "compilerOptions": {
        "allowJs": true,
        "allowSyntheticDefaultImports": true,
        "checkJs": false,
        "declaration": true,
        "esModuleInterop": true,
        "forceConsistentCasingInFileNames": true,
        "inlineSources": false,
        "isolatedModules": true,
        "module": "ESNext",
        "moduleResolution": "Bundler",
        "noImplicitAny": false,
        "noUnusedLocals": false,
        "noUnusedParameters": false,
        "preserveWatchOutput": true,
        "resolveJsonModule": true,
        "preserveSymlinks": false,
        "skipLibCheck": true,
        "strict": true,
        "strictBindCallApply": false,
        "strictNullChecks": false,
        "strictPropertyInitialization": false,
        "strictFunctionTypes": false,
        "useUnknownInCatchVariables": false,
        "target": "es6"
    }
}
yashsway commented 7 months ago

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:

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.

ar7casper commented 5 months ago

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

amritk commented 5 months ago

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

Same here, just started seeing it all of a sudden. strange

izzetemredemir commented 5 months ago

Same here for Version 5.3.3

Luna-devv commented 5 months ago

same for me, "typescript": "^5.3.3" and pnpm 8.11.0 image

leonardo-motta-deel commented 4 months ago

same here

Liubasara commented 4 months ago

same here

laterdayi commented 4 months ago

Several years later, the problem still persists

theMasix commented 4 months ago

same here.

pkerschbaum commented 4 months ago

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

akifunal commented 4 months ago

Same here with typescript 5.3.3 and pnpm 8.14.0

Dorianslavov commented 4 months ago

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' {}
pkerschbaum commented 4 months ago

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' {}

Interesting, didn't hear about this workaround yet!

I tried it out and unfortunately, the emitted declaration files are broken then. I added it as workaround #8 here, you can check it out https://github.com/microsoft/TypeScript/issues/47663#issuecomment-1519138189.

ShayDavidson commented 3 months ago

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)

ackvf commented 3 months ago

My problem is rather confusing

This works

// tailwind.config.ts
import { themeVariants } from 'tailwindcss-theme-variants'
import { type Config } from 'tailwindcss'

const config: Config = { /* ... */ }

export default config

This doesn't work

const config = { /* ... */ } as const satisfies Config

I would prefer the inferred version due to infinitely better intellisense. What options do I have?

todor-a commented 3 months ago

The project I was working on extended a config that had "declaration": true, which was causing this.

rehdie commented 3 months ago

My problem was a stupid Windows-Problem: the error occurred in a jenkins build and the root-cause of the error was a too long path.

In our case we have an Angular module built with the maven frontend-plugin. The path, where the build was executed, was

C:\Jenkins\workspace\vgwort\JERRY\Release Management\Release eines Moduls\target\checkout\hf.webclient

and the error was

18:07:13  [INFO] [INFO] projects/jerry/hf-init/src/lib/hf.menu.ts:20:14 - error TS2742: The inferred type of 'HF_MENU' cannot be named without a reference to '.pnpm/@angular+core@15.2.1_rxjs@7.8.0_zone.js@0.11.4/node_modules/@angular/core'. This is likely not portable. A type annotation is necessary.

Executing the build in

C:\Jenkins\workspace\vgwort\JERRY\Release Management\Release eines Moduls\hf.webclient

works fine. Maybe this helps....

andymerskin commented 3 months ago

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

Threebow commented 3 months ago

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.

Carnewal commented 3 months ago

I am having this issue as well, on v5.3.3. ... 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.

@Threebow I spent some time trying to solve it for the redis package but wasn't succesful. However, you can fix this by installing & using @redis/client (and other redis packages you rely on) directly instead of redis / node-redis. Good luck!

gabrielcosi commented 2 months ago

Same problem when building a react library alongside styled-components with tsup

lovrozagar commented 2 months ago

Same problem here

alvis commented 2 months ago

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

Dorianslavov commented 2 months ago

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

LOWE-7566 commented 1 month ago

use type casting it is always solved in that way

matheo commented 1 month ago
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.

pkerschbaum commented 1 week ago

FYI there is some interesting discussion on this topic in microsoft/TypeScript#58176.

I find this idea for a solution by @eps1lon interesting (which is kind of bringing workaround #3.1 of my comment above into tsc itself):

Is there an option to enforce that whatever getMakeSubDep returns, is also exported from other_package? Then TypeScript could reference those exports instead. It should already do that today if you explicitly export the return type. But TypeScript favors import('sub_dep').Options over import('other_package').Options even if other_package explicitly exports Options.

cumt-robin commented 1 week ago

ๆ‚จ็š„้‚ฎไปถๆˆ‘ๅทฒๆ”ถๅˆฐ๏ผย  ๆˆ‘ไผšๅœจ็ฌฌไธ€ๆ—ถ้—ดๅ†…ๅ›žๅคๆ‚จ๏ผ้žๅธธๆ„Ÿ่ฐข๏ผ