import-js / eslint-plugin-import

ESLint plugin with rules that help validate proper imports.
MIT License
5.46k stars 1.56k forks source link

[import/no-unresolved] when using with typescript and "paths" option #2405

Closed kristijorgji closed 2 years ago

kristijorgji commented 2 years ago

I get [import/no-unresolved] error with eslint while using typescript tsconfig.json paths option.

nextjs + typescript + eslint

My eslint file

module.exports = {
    root: true,
    parser: '@typescript-eslint/parser',
    parserOptions: {
        ecmaFeatures: { jsx: true },
    },
    extends: [
        'eslint:recommended',
        'plugin:@typescript-eslint/eslint-recommended',
        'plugin:@typescript-eslint/recommended',
        'plugin:react/recommended',
        'plugin:jsx-a11y/recommended',
        'plugin:import/errors',
        'plugin:import/warnings',
        'plugin:import/typescript',

        // Prettier plugin and recommended rules
        'plugin:prettier/recommended',
    ],
    rules: {
        // Include .prettierrc.js rules
        'prettier/prettier': ['error', {}, { usePrettierrc: true }],

        'no-empty': 'off',
        'react/prop-types': 'off',
        '@typescript-eslint/ban-ts-comment': 'off',
        '@typescript-eslint/no-non-null-assertion': 'off',
        'jsx-a11y/click-events-have-key-events': 'off',
        'jsx-a11y/no-static-element-interactions': 'off',
        'jsx-a11y/interactive-supports-focus': 'off',
        'jsx-a11y/no-noninteractive-element-interactions': 'off',
        'jsx-a11y/no-onchange': 'off',
    },
    settings: {
        'import/extensions': ['.js', '.jsx', '.tsx', '.ts'],
        'import/resolver': {
            typescript: {},
        },
    },
};

In tsconfig.json i use paths

"paths": {
      "@/core/*": ["src/core/*"],
}

and get errors from eslint like

  18:23  error  Unable to resolve path to module '@/core/useRouter'                  import/no-unresolved

Compilation build all works great, just linting fails eslint

SalahAdDin commented 2 years ago

It does not work with bare React and Typescript setup.

I tried all solutions I found on StackOverflow and the linked issue, and I could not make it work.

skworden commented 2 years ago

Do you have your baseUrl set in tsconfig?

"baseUrl": ".",
"paths": {
      "@/core/*": ["src/core/*"],
}

I can get the module to resolve or eslint to work, not both simultaneously. It builds fine when eslint works and vscode can't find the module.

I'm using turborepo, next, eslint, and typescript

SalahAdDin commented 2 years ago

turborepo

I'm using "baseUrl": "src", it should work, isn't it?

tettoffensive commented 2 years ago

Do you have your baseUrl set in tsconfig?

"baseUrl": ".",
"paths": {
      "@/core/*": ["src/core/*"],
}

I can get the module to resolve or eslint to work, not both simultaneously. It builds fine when eslint works and vscode can't find the module.

I'm using turborepo, next, eslint, and typescript

Did you figure this out? I also have an issue with eslint showing the error in vscode, but it otherwise compiles and the error goes away for a bit when I run eslint with a file open. Reopening the file causes the error to come back.

SalahAdDin commented 2 years ago

Do you have your baseUrl set in tsconfig?

"baseUrl": ".",
"paths": {
      "@/core/*": ["src/core/*"],
}

I can get the module to resolve or eslint to work, not both simultaneously. It builds fine when eslint works and vscode can't find the module.

I'm using turborepo, next, eslint, and typescript

Mine is this:

"baseUrl": "src",
  "paths": {
    "@/application/*": ["application/*"],
    "@/domain/*": ["domain/*"],
    "@/presentation/*": ["presentation/*"]
  },

Do you have your baseUrl set in tsconfig?

"baseUrl": ".",
"paths": {
      "@/core/*": ["src/core/*"],
}

I can get the module to resolve or eslint to work, not both simultaneously. It builds fine when eslint works and vscode can't find the module. I'm using turborepo, next, eslint, and typescript

Did you figure this out? I also have an issue with eslint showing the error in vscode, but it otherwise compiles and the error goes away for a bit when I run eslint with a file open. Reopening the file causes the error to come back.

And yeah, it compiles, not problem with it, but eslint still gives the problem.

loweoj commented 2 years ago

On the plugin docs (https://github.com/alexgorbatchev/eslint-import-resolver-typescript):

Adding

  settings: {
    "import/parsers": {
      "@typescript-eslint/parser": [".ts", ".tsx"],
    },
    "import/resolver": {
      typescript: {},
    },
  },

has worked for me - the import/parsers bit seemed to fix it.

this is with "eslint-import-resolver-typescript": "^2.7.1",

ilya-adnymics commented 2 years ago

@loweoj's solution worked for me. Thanks!

ljharb commented 2 years ago

This seems answered.

If there's changes to the docs that would help here, a PR is most welcome.

SalahAdDin commented 2 years ago

Do you have your baseUrl set in tsconfig?

"baseUrl": ".",
"paths": {
      "@/core/*": ["src/core/*"],
}

I can get the module to resolve or eslint to work, not both simultaneously. It builds fine when eslint works and vscode can't find the module. I'm using turborepo, next, eslint, and typescript

Mine is this:

"baseUrl": "src",
  "paths": {
    "@/application/*": ["application/*"],
    "@/domain/*": ["domain/*"],
    "@/presentation/*": ["presentation/*"]
  },

Do you have your baseUrl set in tsconfig?

"baseUrl": ".",
"paths": {
      "@/core/*": ["src/core/*"],
}

I can get the module to resolve or eslint to work, not both simultaneously. It builds fine when eslint works and vscode can't find the module. I'm using turborepo, next, eslint, and typescript

Did you figure this out? I also have an issue with eslint showing the error in vscode, but it otherwise compiles and the error goes away for a bit when I run eslint with a file open. Reopening the file causes the error to come back.

And yeah, it compiles, not problem with it, but eslint still gives the problem.

I was not putting it inside of the compiler settings.

maikelvl commented 2 years ago

In case you have a custom path tsconfig, you might want to add it to typescript.project as found in https://github.com/import-js/eslint-plugin-import/issues/2301#issuecomment-974473228

  settings: {
    "import/resolver": {
      typescript: {
        project: ["tsconfig.base.json"]
      },
    },
  },
liamjsc commented 1 year ago

Facing a similar issue here, I've tried each of the solutions above and no resolution. nextjs + typescript + eslint typescript compiles fine, but eslint throws errors like:

./src/api/auth.ts
1:28  Error: Unable to resolve path to module 'config'.  import/no-unresolved

My repo is set up like

tsconfig.json
.eslintrc.json
src/
- api/
- components/
- config.ts

relevant tsconfig.json:

{
  "compilerOptions": {
    "baseUrl": "src",
  },
  "include": ["next-env.d.ts", "vendor.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}

and .eslintrc.json

{
  "settings": {
    "import/resolver": {
      "typescript": {
        "project": ["tsconfig.json"]
      }
    },
    "import/parsers": {
      "@typescript-eslint/parser": [".ts", ".tsx"]
    }
  },
  "env": {
    "es6": true,
    "jest": true
  },
  "extends": ["next/core-web-vitals", "prettier"],
  "plugins": ["prettier", "import"],
  "globals": {
    "React": "writable"
  },
  "ignorePatterns": ["vercel-ignore.js"],
  "rules": {
    "react/react-in-jsx-scope": "off",
    "@typescript-eslint/no-non-null-assertion": "off",
    "import/no-anonymous-default-export": "off",
    "import/no-unresolved": "error"
  }
}

Anything look off here? Thanks

ljharb commented 1 year ago

@liamjsc yes, you're missing the import/extensions setting, which would need to include .ts.

liamjsc commented 1 year ago

@ljharb thank you! eslint passes now.

Still trying to configure vscode to:

  1. Stop complaining about this syntax. import { baseApiURL } from 'config' has 'config' red underlined, and "problems" includes ts(2307)

    Screen Shot 2022-09-26 at 10 49 41 AM
  2. "quick fix" is suggesting a relative import for cases like this

    Screen Shot 2022-09-26 at 10 48 25 AM

I expect these may not be related to eslint or import-js, but if you have a suggestion I am stuck here. thanks

JounQin commented 1 year ago

@liamjsc You may need to reload VSCode.

SalahAdDin commented 1 year ago

@liamjsc You may need to reload VSCode.

@liamjsc did you try this?

liamjsc commented 1 year ago

@JounQin @SalahAdDin yes, unplug it and plug it back in 😮‍💨

Thanks for the followup

damiangreen commented 1 year ago

I've tried all the suggestions above and still get this error. Can anyone help

// ESLint configuration
// http://eslint.org/docs/user-guide/configuring
// eslint-disable-next-line
const path = require('path')

module.exports = {
  parser: '@typescript-eslint/parser',
  parserOptions: {
    warnOnUnsupportedTypeScriptVersion: false,
  },
  extends: [
    'airbnb',
    'plugin:@typescript-eslint/recommended',
    'plugin:react/recommended',
    'plugin:css-modules/recommended',
    'prettier',
    'plugin:storybook/recommended',
    //'plugin:unicorn/recommended',
  ],
  plugins: [
    'css-modules',
    'prettier',
    'graphql',
    '@typescript-eslint',
    'formatjs',
    'react-hooks',
    'unused-imports',
    'testing-library',
    'unicorn',
  ],
  overrides: [
    {
      // 3) Now we enable eslint-plugin-testing-library rules or preset only for matching files!
      files: ['**/__tests__/**/*.[jt]s?(x)', '**/?(*.)+(spec|test).[jt]s?(x)'],
      extends: ['plugin:testing-library/react'],
      rules: {
        'testing-library/no-unnecessary-act': 'warn',
        'testing-library/prefer-find-by': 'warn',
        'testing-library/prefer-screen-queries': 'warn',
        'testing-library/await-async-query': 'warn',
        'testing-library/render-result-naming-convention': 'warn',
        'testing-library/no-node-access': 'off',
        // re-enable in future when less noisy
        'testing-library/no-container': 'off',
        // re-enable in future when less noisy
        'testing-library/no-wait-for-side-effects': 'warn',
        'testing-library/no-render-in-setup': 'warn',
        'testing-library/no-wait-for-multiple-assertions': 'warn',
        'testing-library/no-wait-for-snapshot': 'warn',
      },
    },
    {
      files: ['*.ts', '*.tsx', '*.mjs'],
      parserOptions: {
        project: ['./tsconfig.json', './packages/rmm-helpers/tsconfig.json'],
      },
    },
  ],
  globals: {
    __DEV__: true,
    __MAINT__: true,
  },
  env: {
    browser: true,
    jest: true,
  },
  rules: {
...
    'import/extensions': 'off',
    // TODO: Figure out why this started breaking
    'import/order': [
      'error',
      {
        'newlines-between': 'never',
        alphabetize: {
          order: 'asc',
          caseInsensitive: true,
        },
        pathGroups: [
          {
            pattern: 'react',
            group: 'external',
            position: 'before',
          },
          {
            pattern: '*.css',
            group: 'unknown',
            patternOptions: {
              matchBase: true,
            },
            position: 'after',
          },
        ],
        pathGroupsExcludedImportTypes: ['react'],
      },
    ],
    'unused-imports/no-unused-imports-ts': 2,
    'no-unused-expressions': 'off',
    '@typescript-eslint/no-unused-expressions': 'error',
    'prefer-template': 2,
    'graphql/template-strings': [
      'error',
      {
        // Import default settings for your GraphQL client. Supported values:
        // 'apollo', 'relay', 'lokka', 'fraql', 'literal'
        // env: 'literal',
        // Import your schema JSON here
        // schemaJson: require('./src/generated/schema.json'), // TODO: do we need this line?>
        // OR provide absolute path to your schema JSON (but not if using `eslint --cache`!)
        schemaJsonFilepath: path.resolve(
          __dirname,
          './src/generated/schema.json',
        ),
        // OR provide the schema in the Schema Language format
        // schemaString: printSchema(schema),
        tagName: 'graphql', // tagName is gql by default
      },
    ],
    // https://github.com/formatjs/formatjs/issues/785
    // react-intl some components use 'style' prop
    'react/style-prop-object': [
      'error',
      {
        allow: [
          'FormattedNumber',
          'FormattedDateParts',
          'FormattedRelativeTime',
        ],
      },
    ],
  },
  settings: {
    'import/parsers': {
      '@typescript-eslint/parser': ['.ts', '.tsx'],
    },
    'import/extensions': ['.js', '.jsx', '.tsx', '.ts'],
    // Allow absolute paths in imports, e.g. import Button from 'components/Button'
    // https://github.com/benmosher/eslint-plugin-import/tree/master/resolvers
    'import/resolver': {
      typescript: {}, // this loads <rootdir>/tsconfig.json to eslint
      node: {
        moduleDirectory: ['node_modules', 'src', 'packages/rmm-helpers/src'],
        extensions: ['.js', '.tsx', '.ts'],
      },
    },
    'css-modules': {
      basePath: 'src',
    },
  },
}

my root tsconfig.json

{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "rmm-helpers": ["../packages/rmm-helpers/lib"]
     },
    "allowJs": true,
    "outDir": "./lib",
    "allowSyntheticDefaultImports": true,
    "lib": ["es5", "es6", "es7", "es2020", "es2021", "dom"],
    "sourceMap": true,
    "noEmitHelpers": false, // this need true for unit test
    "noImplicitAny": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "esModuleInterop": true,
    "module": "esnext",
    "resolveJsonModule": true,
    "target": "es6",
    "downlevelIteration": true,
    "moduleResolution": "node",
    "jsx": "react-jsx",
    "skipLibCheck": true,
    "noErrorTruncation": true,
    "assumeChangesOnlyAffectDirectDependencies": true,
    // "strictNullChecks": true
    //"strict": true // Enable soon
    "plugins": [
      {
        "name": "typescript-plugin-css-modules",
        "options": {
          "customMatcher": "\\.css$",
        }
      }
    ]
  },
  "include": ["./src/**/*", "./tools/**/*", "./.storybook/*", "./packages/rmm-helpers/**/*"], //, "./packages/rmm-generated/*"
    "references": [
      { "path": "./packages/rmm-helpers" },
    ],
}

My referenced typescript project tsconfig.json

{
  "extends": "../../tsconfig.settings.json",
  "include": ["./src/**/*"],
  "compilerOptions": {
    "outDir": "./lib",
    "rootDir": "./src"
  },
}
karolis-sh commented 1 year ago

@damiangreen to my understanding, this plugin doesn't completely resolve tsconfig when it's being extended, try:

{
  "settings": {
    "import/resolver": {
      "typescript": {
        "project": ["../../tsconfig.settings.json"]
      }
    }
  }
}

Had similar issues in SvelteKit project and this solved it:

{
  settings: {
    'svelte3/typescript': () => require('typescript'),
    'import/resolver': {
      typescript: {
        project: ['./.svelte-kit/tsconfig.json'],
      },
    },
  },
}
ljharb commented 1 year ago

@karolis-sh it should, via tsconfig-paths.

karolis-sh commented 1 year ago

@ljharb when the paths compiler option is placed in a tsconfig that is being extended from, it doesn't seem to resolve that.

Having

tsconfig.json

{
  "extends": "./.svelte-kit/tsconfig.json",
  "compilerOptions": {
    "allowJs": true,
    "checkJs": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "sourceMap": true,
    "strict": true,
    "noImplicitReturns": true,
    "noUncheckedIndexedAccess": true,
    "noUnusedLocals": true,
    "stripInternal": true
  }
}

and ./.svelte-kit/tsconfig.json

{
  "compilerOptions": {
    "paths": {
      "$lib": ["../src/lib"],
      "$lib/*": ["../src/lib/*"]
    },
    ...
  }
}

This fails

  settings: {
    'svelte3/typescript': () => require('typescript'),
    'import/resolver': {
      typescript: {
        project: ['./tsconfig.json'],
      },
    },
  },

as 3:22 error Unable to resolve path to module '$lib/components/Footer.svelte' import/no-unresolved

While this works

  settings: {
    'svelte3/typescript': () => require('typescript'),
    'import/resolver': {
      typescript: {
        project: ['./.svelte-kit/tsconfig.json'],
      },
    },
  },

🤷

ljharb commented 1 year ago

interesting, ok - maybe that's a feature in v4 of tsconfig-paths and we're stuck on v3.

scorsi commented 1 year ago

@karolis-sh is it still working on your side ? When I try your solution I got Unable to resolve path to module on every single imports even from modules...

Here's my full eslint config:

module.exports = {
    root: true,
    parser: "@typescript-eslint/parser",
    extends: [
        "eslint:recommended",
        "plugin:@typescript-eslint/recommended",
        "prettier",
        "plugin:import/recommended",
        "plugin:import/typescript",
    ],
    plugins: ["svelte3", "@typescript-eslint"],
    ignorePatterns: ["*.cjs"],
    overrides: [{ files: ["*.svelte"], processor: "svelte3/svelte3" }],
    settings: {
        "svelte3/typescript": () => require("typescript"),
        "import/resolver": {
            typescript: {
                project: ["./.svelte-kit/tsconfig.json"],
            },
        },
    },
    rules: {
        "import/order": [
            "error",
            {
                groups: ["builtin", "external", "internal", ["sibling", "parent"], "index", "unknown"],
                "newlines-between": "always",
                alphabetize: {
                    order: "asc",
                    caseInsensitive: true,
                },
            },
        ],
    },
    parserOptions: {
        sourceType: "module",
        ecmaVersion: 2020,
    },
    env: {
        browser: true,
        es2017: true,
        node: true,
    },
};

To remove errors, I have to remove the resolver + import/no-unresolved": "off".

ljharb commented 1 year ago

@scorsi the import/resolver settings should include node: {} after the typescript resolver.

scorsi commented 1 year ago

@scorsi the import/resolver settings should include node: {} after the typescript resolver.

It partially fixes my issue, still have Unable to resolve path to module '$app/environment', which is declared like so in ambient.d.ts included in "./.svelte-kit/tsconfig.json":

declare module '$app/environment' {}
Capture d’écran 2023-05-01 à 15 04 05

What a mess...

Doug-Colin commented 11 months ago

What worked for me (Vite, React, and TypeScript):

Notes:

Configs

export default defineConfig({ / Resolve path alias. / resolve: { alias: {
"@": path.resolve(__dirname, "./src"), }, }, server: { proxy: { / My proxy config/ } } });