Skip to content

Bug: error TS2742 in eslint.config.mjs with "composite": true and pnpm #10893

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
4 tasks done
andersk opened this issue Feb 27, 2025 · 5 comments
Open
4 tasks done

Bug: error TS2742 in eslint.config.mjs with "composite": true and pnpm #10893

andersk opened this issue Feb 27, 2025 · 5 comments
Labels
accepting prs Go ahead, send a pull request that resolves this issue bug Something isn't working good first issue Good for newcomers package: typescript-eslint Issues related to the typescript-eslint package

Comments

@andersk
Copy link
Contributor

andersk commented Feb 27, 2025

Before You File a Bug Report Please Confirm You Have Done The Following...

  • I have tried restarting my IDE and the issue persists.
  • I have updated to the latest version of the packages.
  • I have searched for related issues and found none that matched my issue.
  • I have read the FAQ and my problem is not listed.

Issue Description

In a project configured with "composite": true and installed with pnpm, TypeScript flags error TS2742 in this minimal eslint.config.mjs.

// @ts-check
import tseslint from "typescript-eslint";
export default tseslint.config(tseslint.configs.recommended);

eslint.config.mjs:3:1 - error TS2742: The inferred type of 'default' cannot be named without a reference to '.pnpm/@typescript-eslint+utils@8.25.0_eslint@9.21.0_typescript@5.7.3/node_modules/@typescript-eslint/utils/ts-eslint'. This is likely not portable. A type annotation is necessary.

Full tsconfig.json:

{
  "compilerOptions": {
    "allowJs": true,
    "composite": true,
    "module": "nodenext",
    "noEmit": true,
    "strict": true
  }
}

The error is not shown without "composite": true, nor is it shown when using npm instead of pnpm.

Related:

Reproduction Repository Link

https://gist.github.com/andersk/44d8dd0d3c2508f758bf51e5cbf12c2f

Repro Steps

$ git clone https://gist.github.com/andersk/44d8dd0d3c2508f758bf51e5cbf12c2f test
$ cd test
$ pnpm i
Packages: +116
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Progress: resolved 116, reused 116, downloaded 0, added 116, done

dependencies:
+ eslint 9.21.0
+ typescript 5.7.3
+ typescript-eslint 8.25.0

Done in 1.9s using pnpm v10.5.1

$ pnpm exec tsc
eslint.config.mjs:3:1 - error TS2742: The inferred type of 'default' cannot be named without a reference to '.pnpm/@typescript-eslint+utils@8.25.0_eslint@9.21.0_typescript@5.7.3/node_modules/@typescript-eslint/utils/ts-eslint'. This is likely not portable. A type annotation is necessary.

3 export default tseslint.config(tseslint.configs.recommended);
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


Found 1 error in eslint.config.mjs:3

Versions

package version
@typescript-eslint/eslint-plugin 8.25.0
@typescript-eslint/parser 8.25.0
@typescript-eslint/scope-manager 8.25.0
@typescript-eslint/typescript-estree 8.25.0
@typescript-eslint/type-utils 8.25.0
@typescript-eslint/utils 8.25.0
TypeScript 5.7.3
ESLint 9.21.0
node 22.14.0
@andersk andersk added bug Something isn't working triage Waiting for team members to take a look labels Feb 27, 2025
@bradzacher
Copy link
Member

This is very similar to an issue that eslint upstream also had. Pnpm's linking installs plays a bit funky with typescript so it needs the package to declare some additional type exports for it to work.

@bradzacher bradzacher added good first issue Good for newcomers accepting prs Go ahead, send a pull request that resolves this issue package: typescript-eslint Issues related to the typescript-eslint package and removed triage Waiting for team members to take a look labels Feb 27, 2025
@fdendorfer
Copy link

I had the same error, but using a slightly different setup without tseslint.config(). I solved it by adding "eslint.config.mjs" to the exclude array in my tsconfig.json.

@ntnyq
Copy link
Contributor

ntnyq commented Mar 13, 2025

Upstream related issue:

eslint/eslint#19421

ESLint recommended workaround:
https://eslint.org/docs/latest/use/getting-started#manual-set-up

@fdendorfer
Copy link

Thanks for the hint @ntnyq

I can confirm this also works for me

@ntdiary
Copy link
Contributor

ntdiary commented May 29, 2025

Hi, I've looked into this good first issue this week, and hope the following information helps :)
Here is the root cause analysis:

  1. composite: true implies declaration: true by default, which makes typescript assume you'll generate a .d.mts for eslint.config.mjs, maybe like:
    declare const _default: import("@typescript-eslint/utils/ts-eslint").FlatConfig.ConfigArray;
    export default _default;
  2. the default node-linker=isolated means dependencies are symlinked from the .pnpm directory.
  3. and since @typescript-eslint/utils isn't in the project's runtime dependencies (i.e.,package.json), typescript can only recognize the real path that has a nested node_modules, rather than convert it to its simpler symlink path, which finally leads to the TS2742 error1.
    @typescript-eslint/utils -> ../.pnpm/@typescript-eslint+utils@xxx/node_modules/@typescript-eslint/utils

Based on those, here are a few ways to address this issue—(just select the one suits your project):

  1. exclude eslint.config.mjs in your tsconfig.json
    This lets typescript know you don’t need the eslint.config.d.mts file, you can use either include or exclude (might need to be aware that the latter has default values).

    "include": [
      // only include ts files
      "*.ts",
    ]
    "exclude": [
      // other items,
      "eslint.config.mjs",
    ],
  2. set node-linker=hoisted in your .npmrc (as previous comment suggested)
    you will get a flat node_modules without symlinks are created, just like npm or yarn.

  3. run pnpm install @typescript-eslint/utils to make this dependency explicit.
    this allows typescript to recognize its symlink mentioned above (as typescript automatically reads the dependencies in package.json)

  4. export FlatConfig namespace from typescript-eslint
    this package is already in the dependencies, so typescript can correctly recognize its symlink. BTW, I saw that exporting FlatConfig was approved in issue #10848, and that PR hasn’t been updated yet, so not sure about what next steps will be, but I’d be happy to send a PR if needed.

Footnotes

  1. source code image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
accepting prs Go ahead, send a pull request that resolves this issue bug Something isn't working good first issue Good for newcomers package: typescript-eslint Issues related to the typescript-eslint package
Projects
None yet
Development

No branches or pull requests

5 participants