Search code examples
node.jsreactjstypescripttypescript-eslint

How can I fix "ESLint couldn't determine the plugin "@typescript-eslint" uniquely"?


I'm trying to enable eslint linting in an ASP.NET core MVC project with React.js and typescript and am really struggling to fix the above error.

I'm using Visual Studio 2022 community edition 17.6.3 and the project template "ASP.NET Core with React.js", which in turn uses create-react-app to create a React.js application in a ClientApp subfolder of the project folder.

This is the error message as reported by yarn. Similar error messages have appeared at the top of my code editor tabs when editing .tsx code files, but yarn seems to report the most comprehensive message.

yarn run v1.22.19 $ eslint ./src/

Oops! Something went wrong! :(

ESLint: 8.48.0

ESLint couldn't determine the plugin "@typescript-eslint" uniquely.

  • C:\path\to\MyProject\ClientApp\node_modules@typescript-eslint\eslint-plugin\dist\index.js (loaded in "src.eslintrc.json")
  • C:\path\to\MyProject\ClientApp\node_modules\eslint-config-react-app\node_modules@typescript-eslint\eslint-plugin\dist\index.js (loaded in "src.eslintrc.json » eslint-config-react-app#overrides[0]")

Please remove the "plugins" setting from either config or remove either plugin installation.

My current understanding of this message is that the compiler has detected that different parts of my project expect different versions of @typescript-eslint and doesn't know which version to use (but I could be wrong about that and am more than happy to be corrected).

I am particularly curious to understand how to read this part of the error message:

(loaded in "src.eslintrc.json » eslint-config-react-app#overrides[0]")

This seems to imply that my .eslintrc.json file contains something like

{
    eslint-config-react-app: {
        overrides: [
            // ???
        ]
    }
}

... except that said file contains nothing of the sort. Again, I could be reading the error message incorrectly and am more than happy to be corrected on that point.

What I've tried

My configuration

package.json

{
  "name": "myapp",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "bootstrap": "^5.3.1",
    "http-proxy-middleware": "^2.0.6",
    "jquery": "^3.7.0",
    "merge": "^2.1.1",
    "oidc-client": "^1.11.5",
    "react": "^18.2.0",
    "react-bootstrap": "^2.8.0",
    "react-dom": "^18.2.0",
    "react-in-viewport": "^1.0.0-alpha.30",
    "react-router-bootstrap": "^0.26.2",
    "react-router-dom": "^6.15.0",
    "reactstrap": "^9.2.0",
    "rimraf": "^5.0.1",
    "web-vitals": "^3.4.0"
  },
  "devDependencies": {
    "@babel/eslint-parser": "^7.22.11",
    "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
    "@types/jest": "^29.5.4",
    "@types/react": "^18.2.21",
    "@typescript-eslint/eslint-plugin": "^6.4.1",
    "@typescript-eslint/parser": "^6.4.1",
    "ajv": "^8.12.0",
    "cross-env": "^7.0.3",
    "eslint": "^8.48.0",
    "eslint-plugin-flowtype": "^8.0.3",
    "eslint-plugin-import": "^2.28.1",
    "eslint-plugin-jest": "^27.2.3",
    "eslint-plugin-jest-formatting": "^3.1.0",
    "eslint-plugin-jsdoc": "^46.5.0",
    "eslint-plugin-jsx-a11y": "^6.7.1",
    "eslint-plugin-react": "^7.33.2",
    "nan": "^2.17.0",
    "react-scripts": "^5.0.1",
    "typescript": "4.3.5"
  },
  "jest": {
    "coveragePathIgnorePatterns": [
      "/src/index.js",
      "/src/reportWebVitals.js",
      "/src/service-worker.js",
      "/src/serviceWorkerRegistration.js",
      "/src/setupProxy.js",
      "/src/components/",
      "/src/Models"
    ],
    "coverageReporters": [
      "json",
      "html",
      "text"
    ]
  },
  "overrides": {
    "autoprefixer": "10.4.5",
    "semver": "^7.5.2",
    "svgo": "^2.0.0"
  },
  "resolutions": {
    "css-what": "^5.0.1",
    "nth-check": "^2.0.0"
  },
  "scripts": {
    "prestart": "node aspnetcore-https && node aspnetcore-react",
    "start": "rimraf ./build && react-scripts start",
    "build": "react-scripts build",
    "test": "cross-env CI=true react-scripts test --env=jsdom",
    "watch": "cross-env CI=true react-scripts test --env=jsdom --watchAll --coverage",
    "eject": "react-scripts eject",
    "lint": "eslint ./src/"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "peerDependencies": {
    "@babel/core": "^7.11.0",
    "@babel/plugin-syntax-flow": "^7.14.5",
    "@babel/plugin-transform-react-jsx": "^7.14.9",
    "@popperjs/core": "^2.11.8"
  }
}

.eslintrc.json

{
  "parser": "@typescript-eslint/parser",
  "extends": [
    "eslint:recommended",
    "plugin:import/errors",
    "plugin:import/warnings",
    "plugin:react/recommended",
    "plugin:jsdoc/recommended",
    "react-app"
  ],
  "env": {
    "browser": true,
    "node": true,
    "mocha": true,
    "es6": true,
    "jest": true
  },
  "overrides": [
    {
      "files": [
        "**/*.test.js"
      ],
      "env": {
        "jest": true
      },
      "plugins": [
        "jest",
        "jest-formatting"
      ],
      "rules": {
        // Omitted for brevity, I can edit them back in if needed
      }
    }
  ],
  "plugins": [
    "react",
    "import",
    "jsx-a11y",
    "jest",
    "jsdoc",
    "@typescript-eslint"
  ],
  "parserOptions": {
    "ecmaVersion": 6,
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true
    }
  },
  "rules": {
    // Omitted for brevity, I can edit them back in if needed
  },
  "settings": {
    "react": {
      "version": "18"
    },
    "import/resolver": {
      "node": {
        "extensions": [ ".js", ".jsx", ".ts", ".tsx" ]
      }
    }
  }
}

tsconfig.json

{
  "compilerOptions": {
    "target": "ES6",
    "lib": ["es6", "DOM"],
    "jsx": "react",
    "module": "commonjs",
    "moduleResolution": "node",
    "types": ["jest", "node", "@types/jest"],
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "skipDefaultLibCheck": true,
    "skipLibCheck": true
  }
}

Solution

  • Credit to Brad Zacher's answer for drawing my attention to How do I check to see what versions are installed?

    If you have multiple versions of our tooling, it can cause various bugs for you. This is because ESLint may load a different version each run depending on how you run it - leading to inconsistent lint results.

    Installing our tooling in the root of your project does not mean that only one version is installed. One or more of your dependencies may have its own dependency on our tooling, meaning npm/yarn will additionally install that version for use by that package. For example, react-scripts (part of create-react-app) has a dependency on our tooling.

    You can check what versions are installed in your project using the following commands:

    npm npm list @typescript-eslint/eslint-plugin @typescript-eslint/parser

    Yarn yarn list --pattern "@typescript-eslint/eslint-plugin|@typescript-eslint/parser"

    pnpm pnpm list @typescript-eslint/eslint-plugin @typescript-eslint/parser

    If you see more than one version installed, then you will have to either use yarn resolutions to force a single version, or you will have to downgrade your root versions to match the dependency versions.

    The best course of action in this case is to wait until your dependency releases a new version with support for our latest versions.

    I used the yarn command, which gave the following output

    yarn list v1.22.19
    ├─ @typescript-eslint/[email protected]
    ├─ @typescript-eslint/[email protected]
    └─ [email protected]
       ├─ @typescript-eslint/[email protected]
       └─ @typescript-eslint/[email protected]
    

    So the solution was to downgrade @typescript-eslint/eslint-plugin and @typescript-eslint/parser to version 5.62.0 in my package.json, to match the version used by eslint-config-react-app.

    I then hit a different error:

    There was a problem loading formatter: ...\node_modules\eslint\lib\cli-engine\formatters\stylish Error: require() of ES Module ...\node_modules\strip-ansi\index.js from ...\assertion-lib\node_modules\eslint\lib\cli-engine\formatters\stylish.js not supported. Instead change the require of index.js in ...\node_modules\eslint\lib\cli-engine\formatters\stylish.js to a dynamic import() which is available in all CommonJS modules.

    Manually editing something in the node_modules folder didn't sound right, however it seems that this is a bug in yarn. So I deleted the yarn.lock file from my project and deleted the node_modules folder (which may have been overkill) and ran a npm install and now eslint is linting my typescript code successfully.