reactjsnext.jseslinttypescript-eslint

How to enable eslint inline config in Next.js


I’m working on a Next.js project with TypeScript. It needs to interface with an external JavaScript library that isn’t TypeScript-enabled, which I’m loading by means of Next’s <Script> component. It works fine in development, but when I try to build it, the build fails with the error Type error: Cannot find name 'x'., where x is an object from the external library. I’ve tried declaring types for it but that’s a lot of very fiddly work for little gain, since it’s a well tested library. I’d like to just suppress the lint errors for the problem lines, but I can’t seem to get it working. Here’s what I’ve tried:

  1. Include inline comments per eslint’s documentation.
    // eslint-disable-next-line
    const y = new x.constructor();
    
    or
    const y = new x.constructor(); // eslint-disable-line
    
    (I left this in while trying the rest of this list, since it didn’t work by itself.)
  2. Override Next’s default eslint rules, by creating .eslintrc.json with contents:
    {
      "extends": ["next/core-web-vitals", "next/typescript"],
      "overrides": [
        {
          "files": ["**/*.ts", "**/*.tsx", "**/*.mts"],
          "rules": {
            "no-inline-config": "off"
          }
        }
      ]
    }
    
  3. Modify Next’s eslint config by creating next.config.js with contents:
    module.exports = {
      eslint: {
        "no-online-config": "off",
      },
    }
    
    (This throws a warning, Unrecognized key(s) in object: 'noInlineConfig' at "eslint".)
  4. Hack node_modules/next/bin/dist/bin/next and remove the code .option("--no-inline-config", "Prevents comments from changing config or rules.").

None of these made any difference, except for option 3, which threw a warning. For obvious reasons I don’t want to disable eslint completely, but I can’t see another option if I want this to build. What am I missing?

package.json:

{
  "name": "my-project",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@emotion/react": "^11.13.3",
    "@emotion/styled": "^11.13.0",
    "@mui/icons-material": "^6.1.0",
    "@mui/material": "^6.0.2",
    "@mui/x-charts": "^7.17.0",
    "@mui/x-date-pickers": "^7.16.0",
    "dayjs": "^1.11.13",
    "next": "^14.2.12",
    "nuqs": "^1.20.0",
    "react": "^18",
    "react-dom": "^18"
  },
  "devDependencies": {
    "@types/node": "^20",
    "@types/react": "^18",
    "@types/react-dom": "^18",
    "eslint": "^8",
    "eslint-config-next": "14.2.8",
    "typescript": "^5"
  }
}

Solution

  • Type error: Cannot find name 'x'

    That's not an ESLint report. That's a TypeScript report. Your whole investigation is going down the wrong path. 🙂

    ESLint and TypeScript are both tools that give feedback on your code without running it (this is called "static analysis"). But they're two very tools:

    Any report starting with "Type error:" is a TypeScript type error. The way to suppress TypeScript type errors is with an inline // @ts-expect-error (preferred) or // @ts-ignore (less preferable). See https://www.totaltypescript.com/concepts/how-to-use-ts-expect-error for a good explanation.


    Aside: instead of suppressing the TypeScript type error, it would be better to tell TypeScript about x existing. That way it can give dev-time assistance for x & let you know if you're using it wrong. https://www.typescriptlang.org/docs/handbook/declaration-files/by-example.html has docs. For example, to declare x as a constant object with a .constructor:

    declare const x: {
      constructor: typeof Object; // or typeof whatever class
    }
    

    https://www.typescriptlang.org/play/?#code/CYUwxgNghgTiAEYD2A7AzgF3gDwFzwG8AoeUxVTGAVzAyRnwwE8AHEJAM3gHkAjAK3AYA3EQC+ooihAB3HADpk6DNVr0AFAEphQA