Maxime Dupré
Maxime Dupré

Reputation: 5737

Using eslint with typescript - Unable to resolve path to module

I have this import in my file app.spec.ts:

import app from './app';

Which causes this Typescript error

2:17  error  Unable to resolve path to module './app'  import/no-unresolved

./app.ts does exist, but I have not compiled the .ts file into a .js file. As soon as I compile the .ts file to a .js, the error goes away.

However, since eslint is supposed to work with typescript, it should resolve modules with the .ts and not the .js.

I've also added the typescript information in my eslint config file:

"parser": "@typescript-eslint/parser",
"parserOptions": {
    "project": "./tsconfig.json"
}

How can I config eslint in such a way that it tries to resolve modules with the .ts and not the .js?

EDIT #1

Content of app.ts:

import bodyParser from 'body-parser';
import express from 'express';
import graphqlHTTP from 'express-graphql';
import { buildSchema } from 'graphql';

const app = express();

const schema = buildSchema(`
    type Query {
        hello: String
    }
`);
const root = { hello: () => 'Hello world!' };

app.use(bodyParser());
app.use('/graphql', graphqlHTTP({
    schema,
    rootValue: root,
    graphiql: true,
}));

export default app;

Upvotes: 390

Views: 461199

Answers (24)

user4717662
user4717662

Reputation:

You can set the ESLint module import resolution by adding this snippet to your .eslintrc.json configuration file:

{
  "settings": {
    "import/resolver": {
      "node": {
        "extensions": [".js", ".jsx", ".ts", ".tsx"]
      }
    }
  },
  // ...
}

More informations about resolvers: https://github.com/benmosher/eslint-plugin-import#resolvers.

Upvotes: 637

vitaly tochenyy
vitaly tochenyy

Reputation: 21

This variant of .eslintrc.js configuration hepls me to solve this problem:

   settings: {
      'import/parsers': {
         '@typescript-eslint/parser': ['.ts', '.tsx'],
      },
      'import/resolver': {
         node: {
            extensions: ['.js', '.jsx', '.ts', '.tsx'],
         },
         typescript: {
            alwaysTryTypes: true, // always try to resolve types under `<root>@types` directory even it doesn't contain any source code, like `@types/unist`

            // use an array of glob patterns
            project: ['**/tsconfig.json'],
         },
      },
   }

Oh, and dont forget this:

npm i eslint-import-resolver-typescript

and see the docs - https://www.npmjs.com/package/eslint-import-resolver-typescript

Upvotes: 2

Adande Sylvain
Adande Sylvain

Reputation: 33

  1. Add this to extends:

    "extends": [
      "airbnb-typescript",
    ]
    
  2. Add this to parserOptions:

    "parserOptions": {      
       "project": "./tsconfig.json"
     },
    
  3. Be sure to install the dev module:

    npm i --save-dev eslint-config-airbnb-typescript 
    

Upvotes: 0

mufsalup
mufsalup

Reputation: 28

I´ve spend a lot of hours trying several approaches from this page. But however this did not solve my problem. In my case I am using more then one tsconfig file in a large project.

I was adding eslint-import-resolver-typescript to my project:

npm install eslint-import-resolver-typescript

Afterwards I added this to my eslintrc:

    settings: {
        "import/resolver": {
            typescript: {
                project: ["./path/to/config.json", "./path/to/config2.json", "./path/to/config3.json"] // Pfad zu deiner tsconfig.json-Datei
            }
        }
    },

Upvotes: 0

Znacovean Simion
Znacovean Simion

Reputation: 59

In 2023 this helps me

  env: { browser: true, es2020: true, node: true },
  extends: [
    'plugin:react/recommended',
    'airbnb',
    'airbnb-typescript',
    'airbnb/hooks',
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:react-hooks/recommended',
    'plugin:import/recommended',
    'plugin:import/typescript',
    'prettier',
  ],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    project: './tsconfig.json',
    ecmaVersion: 2018,
    sourceType: 'module',
    ecmaFeatures: {
      jsx: true,
    },
  },
    // Airbnb disable eslint-import-resolver-typescript
    // See: https://github.com/iamturns/eslint-config-airbnb-typescript#why-is-importno-unresolved-disabled
    // But, To support the tsconfig baseUrl and paths for aliasese that we uses,
    // you need this package
    // See configuration here
    // https://github.com/alexgorbatchev/eslint-import-resolver-typescript#installation

    'import/parsers': {
      '@typescript-eslint/parser': ['.ts', '.tsx'],
    },
    'import/resolver': {
      typescript: {
        alwaysTryTypes: true,
      },
    },

Upvotes: 1

Daniel Davidyan
Daniel Davidyan

Reputation: 11

The issue was that the paths were not correctly resolving for the source folder. To solve the problem, I added the father of the source folder to the paths as well.

Instead of:

"settings": {
  "import/resolver": {
    "node": {
      "extensions": [".js", ".jsx", ".ts", ".tsx"],
      "paths": ["src"]
    }
  }
}

I made the following modification:

"settings": {
  "import/resolver": {
    "node": {
      "extensions": [".js", ".jsx", ".ts", ".tsx"],
      "paths": ["src", "client/src"]
    }
  }
}

Explanation: By adding the "client/src" path, the resolver can now correctly locate the files within that directory when importing or resolving modules. This change resolved the path resolution issue I was facing in my project.

(Optional: If applicable, mention where the "settings" block should be placed in your project's configuration file, e.g., webpack.config.js, tsconfig.json, etc.)

I hope this solution helps others who encounter a similar problem!

Upvotes: 1

Max
Max

Reputation: 22315

For me, this error was caused by using eslint-config-airbnb. It isn't set up to work properly with typescript. The best fix for that (from this answer) is to install eslint-config-airbnb-typescript. The npm page includes the setup instructions, which involves tweaking your eslint config to load it and pointing it at your typescript config.

Note that if you used create-react-app to set up your app, you'll have an eslintConfig block in package.json. You need to have one ESLint config. If you create an .eslintrc to set up typescript linting, you should delete the block from package.json and move any config from there into the one config file.

Upvotes: 1

Typhon
Typhon

Reputation: 1056

When importing locale files for Angular (e.g. import localeEn from '@angular/common/locales/en';), I had to allow the .mjs extension.

Here is an excerpt of my .eslintrc.json:

  ...
  "extends": [
    ...
    "plugin:import/recommended",
    "plugin:import/typescript",
    ...
  ],
  "settings": {
    "import/resolver": {
      "node": {
        "extensions": [".ts", ".mjs"]
      }
    }
  },
  "rules": {
    ...
  }
  ...

Edit:

When importing HttpClient or HttpClientModule, the error came back. I found out that adding the .d.ts extension to the list fixed the issue, which also make more sense than the .mjs (that is no longer needed).

So here is my new .eslintrc.json:

  ...

  {
    "files": ["*.ts"],
    "parser": "@typescript-eslint/parser",
    "parserOptions": {
      "project": ["tsconfig.json"],
      "createDefaultProgram": true
    },
    "settings": {
      "import/resolver": {
        "node": {
          "extensions": [".ts", ".d.ts"]
        }
      }
    },
    "extends": [
      "eslint:recommended",
      "plugin:import/recommended",
      "plugin:import/typescript",
      "plugin:@typescript-eslint/recommended",
      "plugin:@angular-eslint/recommended",
      "plugin:@angular-eslint/ng-cli-compat",
      "plugin:@angular-eslint/ng-cli-compat--formatting-add-on",
      "plugin:@angular-eslint/template/process-inline-templates"
    ],
    "rules": {
      ...
    }
  }

  ...

(I'm using @angular-eslint, but you may have a different extends list)

Upvotes: 8

Rafael Rozon
Rafael Rozon

Reputation: 3019

I had the same problem and I was only able to fix it by adding the typescript plugin to .eslintrc, using the extends option in .eslintrc

  extends: [
    "plugin:import/errors",
    "plugin:import/warnings",
    "plugin:import/typescript",
  ],

Upvotes: 255

Katie Byers
Katie Byers

Reputation: 1010

In my case, I had to delete the eslint cache, and then it worked like a charm. (Our yarn script is

"lint:eslint": "eslint . --cache --cache-location '../../eslintcache/' --format stylish"

.)

Upvotes: 0

NeoZoom.lua
NeoZoom.lua

Reputation: 2891

Awesome people know how to solve this by oneliner in 2022:

"rules": {
  "import/extensions": [ "error", "ignorePackages", { "": "never" } ]
}

Upvotes: -21

Pedro A
Pedro A

Reputation: 4313

In my case I just had to change

import { SetOptional, SetRequired } from 'type-fest';

to

import type { SetOptional, SetRequired } from 'type-fest';

Upvotes: 47

YEVY
YEVY

Reputation: 1210

My situation with ts monorepo was that I was not getting lint errors in IDE, all aliases were resolved alright, but as soon as I run eslint on one of the projects, I was getting

error  Unable to resolve path to module

It is important to show eslint path to each of your package's tsconfig file.

To sum up and for those with TS, aliases and monorepo:

  • install eslint-import-resolver-typescript
  • add to eslintrc.js settings (this will help ide and eslint to figure aliases and stuff):
    'import/resolver': {
      node: {
        paths: 'packages/*/src',
        extensions: ['.js', '.jsx', '.ts', '.tsx'],
      },
      typescript: {
        alwaysTryTypes: true,
        project:[
         path.resolve(__dirname, '.tsconfig.json'), // root tsconfig
         path.resolve(__dirname, './packages/projA/tsconfig.json'),
         path.resolve(__dirname, './packages/projB/tsconfig.json'),
         /* ...rest of projects path to its tsconfig */
        ],
      },
  • add to eslintrc.js extends:
{
 ...,
   'plugin:import/recommended',
   'plugin:import/typescript',
}

  • add to eslintrc.js plugins:
  plugins: ['@typescript-eslint', ..., 'import'],
  • add to eslintrc.js parserOptions (same as to settings) this will help eslint:
        project: [
          path.resolve(__dirname, '.tsconfig.json'), // root tsconfig
          path.resolve(__dirname, './packages/projA/tsconfig.json'),
          path.resolve(__dirname, './packages/projB/tsconfig.json'),
          /* ...rest of projects path to its tsconfig */
        ],

Upvotes: 6

Jakob Jan Kamminga
Jakob Jan Kamminga

Reputation: 681

If you've updated your .eslintrc and tsconfig.json files as suggested in the other answers, and you still have the problem - restart vscode.

Upvotes: 27

MegaCookie
MegaCookie

Reputation: 5255

For me it was just simply installing eslint-import-resolver-node:

yarn add -D eslint-import-resolver-node
# or
npm install eslint-import-resolver-node --save-dev

Upvotes: 2

vamcs
vamcs

Reputation: 345

In my case, ESLint wasn't able to resolve the types installed from DefinitelyTyped (@type/ packages), so I had to specify where to find them in .eslintrc like this:

"import/resolver": {
    "typescript": {},
    "node": {
        "extensions": [".js", ".ts"],
        "paths": ["node_modules/", "node_modules/@types"]
    }
},

I also added "typescript": {}, which is basically for using configs from tsconfig.json and I have eslint-import-resolver-typescript installed for it to work.

Upvotes: 6

swapnil kale
swapnil kale

Reputation: 71

First add "plugin:import/typescript" under extends like below :

"extends": [
    "airbnb-base",
    "plugin:import/typescript"
 ],

then below under rules

"rules": {
        "import/extensions": [
            "error",
            "ignorePackages",
            {
                "ts": "never"
            }
        ]
    }

Upvotes: 7

Diogo Capela
Diogo Capela

Reputation: 6560

This was the only solution that worked for me.

First, you need to install this package:

yarn add -D eslint-import-resolver-typescript

Then add this to your .eslintrc file so it can load the alias settings from your tsconfig.json into ESLint:

{
  "settings": {
    "import/resolver": {
      "typescript": {}
    },
  },
}

Upvotes: 157

flashmatrix
flashmatrix

Reputation: 195

I had to add the typescript import to extends and then turn off the imports in the rules:

"extends": {
    "plugin:import/typescript"
},
"rules": {
    "import/extensions": "off"
}

Upvotes: 3

remacr
remacr

Reputation: 698

When using "eslint": "6.8.0" with "typescript": "3.8.3" besides adding the following to .eslintrc:

"settings": {
  "import/resolver": {
    "node": {
      "paths": ["src"],
      "extensions": [".js", ".jsx", ".ts", ".tsx"],
    }
  },
}

You also need to add this line to tsconfig.json under compilerOptions:

"compilerOptions": {
  ...
  // Base directory to resolve non-relative module names.
  "baseUrl": "src",
  ...
}

Upvotes: 32

Josh Weston
Josh Weston

Reputation: 1890

Both ts and eslint were barking at me, so I had to add the following to my .eslintrc file:

{ 
    ...
    "rules": {
        ....
        "import/extensions": "off"
    },
    "settings": {
        ....
        "import/resolver": {
            "node": {
                "extensions": [".js", ".jsx", ".ts", ".tsx"]
            }
        }
    }
}

Upvotes: 12

Yogi
Yogi

Reputation: 1712

In case, if anyone needs to support child directory as well. For an example, it supports

  1. src/components/input => components/input
  2. src/api/external/request => external/request

    "settings": {
      "import/resolver": {
        "node": {
          "paths": ["src", "src/api"],
          "extensions": [".js", ".jsx", ".ts", ".tsx"]
        }
      }
    }
    

This is working example for eslint ^6.1.0

Upvotes: 2

olefrank
olefrank

Reputation: 6810

This does it for me:

.eslintrc.js

{
    ...
    settings: {
        ...
        'import/resolver': {
            node: {
                extensions: ['.js', '.jsx', '.ts', '.tsx'],
                moduleDirectory: ['node_modules', 'src/'],
            },
        },
    }
}

Upvotes: 120

Mr.Ghamkhar
Mr.Ghamkhar

Reputation: 567

for those who use babel-module just add the extensions so it would be something like this:

      "babel-module": {
        "extensions": [".js", ".jsx", ".ts", ".tsx"],
        "alias": {
          "app": "./app"
        }
      }

Upvotes: 13

Related Questions