Skip to content
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

[import/no-extraneous-dependencies] Problems when only using types #1618

Closed
thewilkybarkid opened this issue Jan 20, 2020 · 42 comments · Fixed by #1820 or #2735
Closed

[import/no-extraneous-dependencies] Problems when only using types #1618

thewilkybarkid opened this issue Jan 20, 2020 · 42 comments · Fixed by #1820 or #2735

Comments

@thewilkybarkid
Copy link

thewilkybarkid commented Jan 20, 2020

We've started to see failures when moving from 2.18.2 to 2.20.0 regarding importing only types from devDependencies in TypeScript source code. Previously the rule wasn't triggering for these (which I would expect), but it now is.

Refs libero/article-store#174.

@ljharb
Copy link
Member

ljharb commented Jan 23, 2020

Similar to #1615?

@thewilkybarkid
Copy link
Author

Seems to have started at the same time. #1637 will resolve #1615, but not this.

@thewilkybarkid
Copy link
Author

Went through the commits since 2.18.2 on no-extraneous-dependencies.js, but none of them seem to trigger the problem.

@thewilkybarkid
Copy link
Author

Can confirm this first appears in 2.20.0, and #1615 appears in 2.19.1 (maybe 2.19.0, but that's broken).

@thewilkybarkid
Copy link
Author

Seems that #1526 is cause, reverting the change causes it to pass.

@thewilkybarkid
Copy link
Author

thewilkybarkid commented Jan 30, 2020

To clarify, I have @types/rdf-js and @types/jsonld in devDependencies, and import only types from them in my source TypeScript (so are only needed at compile-time, not runtime). The errors are like:

error  'jsonld' should be listed in the project's dependencies. Run 'npm i -S jsonld' to add it  import/no-extraneous-dependencies
error  'rdf-js' should be listed in the project's dependencies. Run 'npm i -S rdf-js' to add it  import/no-extraneous-dependencies

(The latter being impossible as it doesn't exist.)

My config has:

settings: {
  'import/resolver': {
    typescript: { alwaysTryTypes: true },
  },
},

Without that the errors are:

error  Unable to resolve path to module 'jsonld/jsonld-spec'  import/no-unresolved
error  Unable to resolve path to module 'rdf-js'              import/no-unresolved

@ljharb
Copy link
Member

ljharb commented Jan 30, 2020

The intention of the no-unresolved rule, however, is to never import something that doesn't exist - iow, why is @types/rdf-js not an installed package?

@thewilkybarkid
Copy link
Author

They are both installed.

@thewilkybarkid
Copy link
Author

Just tried moving @types/rdf-js to dependencies (to check what happens), and that doesn't work either.

@ljharb
Copy link
Member

ljharb commented Jan 31, 2020

hmm, which typescript resolver are you using? i believe the unscoped one is deprecated.

@thewilkybarkid
Copy link
Author

2.0.0 (.eslintrc.js, package.json).

@dlong500
Copy link

dlong500 commented Feb 8, 2020

Unless I'm missing some new setting, I believe this (#1526) may be affecting the no-extraneous-dependencies rule even outside of typescript (at least when using vscode). If I add an import statement for any package the no-extraneous-dependencies won't properly identify packages that aren't anywhere in my dependencies if it can find a type definition for them in Microsoft's global TypeScript module path.

For example, I can add an import for ioredis and it resolves to C:/Users/<user>/AppData/Local/Microsoft/TypeScript/3.8/node_modules/@types/ioredis/index.

Maybe I'm just not doing something right? I'm using v2.20.1. I haven't tried to downgrade eslint-plugin-import yet to see if that makes a difference but will soon.

[EDIT] Yep, if I revert back to 2.18.2 then I correctly get the error:
'ioredis' should be listed in the project's dependencies. Run 'npm i -S ioredis' to add iteslint(import/no-extraneous-dependencies)

@ljharb
Copy link
Member

ljharb commented Feb 9, 2020

cc @joaovieira do you have time to take a look at this? I'd prefer not to revert your PR.

@joaovieira
Copy link
Contributor

@dlong500 it should not affect non-typescript setups as it was only applied to the typescript config. If you don't have extends: ['plugin:import/typescript'] in your eslint config, then that change doesn't apply.

I have also tried a minimal repro with your issue and it's working fine for me:

// .eslintrc
module.exports = {
  env: {
    node: true
  },
  extends: [
    'eslint:recommended',
    'plugin:import/recommended',
  ],
  plugins: ['import'],
  settings: {
    'import/resolver': {
      node: {
        paths: ['/Users/joaovieira/.nvm/versions/node/v10.16.3/lib/node_modules']
      }
    }
  },
  rules: {
    'import/no-extraneous-dependencies': 1
  }
};
// package.json
"dependencies": {
  "eslint": "^6.8.0",
  "eslint-plugin-import": "^2.20.1"
}

Screen Shot 2020-02-09 at 21 26 35

Have both ioredis and @types/ioredis installed globally and node index.js runs fine.


Will look into the original issue now. Thanks @ljharb for pinging.

@ljharb
Copy link
Member

ljharb commented Feb 9, 2020

@joaovieira you'll also need the typescript resolver.

@dlong500
Copy link

dlong500 commented Feb 9, 2020

@joaovieira I definitely don't have any typescript rules in my eslint config, so something else must be coming into play. I figured it must have something to do with vscode's Automatic Type Acquisition related to intellisense. I'm also using vscode's nightly (insider) build, so I don't know if that might affect things too.

I'll try to continue testing on my end to see if I can pinpoint anything useful. Sorry, I don't mean to hijack the thread if this isn't directly related to the OP--just not sure where else to post as there is definitely something different between v2.18.2 and v2.20.1.

@ljharb
Copy link
Member

ljharb commented Feb 9, 2020

@dlong500 if you're having issues in vscode, verify on the command line - if it works there, it's a vscode bug only.

@dlong500
Copy link

@dlong500 if you're having issues in vscode, verify on the command line - if it works there, it's a vscode bug only.

Sorry to be a pain, but the issue persists with running eslint from the command line (same difference between v2.18.2 working and v2.20.1 not working). I will try to come up with a test case repo if I can get a bit of time. One thing to point out is that I'm using eslint-import-resolver-babel-module as a resolver.

@joaovieira
Copy link
Contributor

joaovieira commented Feb 10, 2020

@thewilkybarkid @ljharb I believe the current behaviour is correct and this is a bug.

Using the original example:

import { Context as JsonLdContext } from 'jsonld/jsonld-spec';

In both versions it resolves to:

.../node_modules/@types/jsonld/jsonld-spec.d.ts

But it 2.18.2 it was being marked as internal.

#1526 fixed that, so it is now correctly marked as external.

By being external it's now subject to the check of no-extraneous-dependencies according to https://github.com/benmosher/eslint-plugin-import/blob/f790737c07f39058592b7eb8b6cda3de72c239b9/src/rules/no-extraneous-dependencies.js#L118-L120 - which didn't happen before at all.

And because the package name is computed as jsonld (from the import path) rather than @types/jsonld, it is never found in the package deps.

Changing the import to:

import { Context as JsonLdContext } from '@types/jsonld/jsonld-spec';

Would treat it as a scoped module and pass the eslint check, but doesn't make the TS compiler happy.


@ljharb what would you think of trying both jsonld and @types/jsonld if the resolved path contains @types? I know it adds some knowledge of the TS structure, but ExportMap already contains TS logic as well.

@ljharb
Copy link
Member

ljharb commented Feb 10, 2020

Is there any way we could mark it as a TS type (and thus eligible for the dual check) only if the TS resolver marks it as external? ie, so only these cases would get treated as such.

@joaovieira
Copy link
Contributor

joaovieira commented Feb 10, 2020

The resolver knows it's a "definitely typed" module and could add any flag at that point: https://github.com/alexgorbatchev/eslint-import-resolver-typescript/blob/ef5c33d3bc561e1ef34539b752b40de1685e5454/src/index.ts#L86 but I assume the resolvers have a well-defined contract (i.e. return a { path, found } object)?

Though it's actually the import plugin that checks if it's external, but at that point it can't distinguish if it's a "definitely typed" or normal module as its driven by the import/external-module-folders setting which treats them equally.

I can draft a PR tomorrow and discuss there.

@ljharb
Copy link
Member

ljharb commented Feb 10, 2020

A { path, found } object can have extra properties added.

@dlong500
Copy link

So, I've discovered my issue only occurs on Windows (and only with the very latest v2.20.1). The same repo on Linux works fine. I think it is related to #1643. I did create a minimal testing repo here (https://github.com/dlong500/eslint-import-extraneous-issue-simple) in case it is helpful. I'm seeing the same issue show up even with the standard node resolver (no custom resolvers).

Sorry if all this is unrelated to the the actual issue in this thread.

@joaovieira
Copy link
Contributor

joaovieira commented Feb 10, 2020

Funnily enough this plugin already handles type-only imports for Flow (import type), which is now coming to TS (https://devblogs.microsoft.com/typescript/announcing-typescript-3-8-beta/#type-only-imports-exports). Type imports are ignored in many places in this plugin, including no-extraneous-dependencies: https://github.com/benmosher/eslint-plugin-import/blob/3b04d5fab6c095e7f0f99488665d90e285872271/src/rules/no-extraneous-dependencies.js#L102-L105

Would be good to treat them the same way (between Flow and TS), but we have to wait for that to be available in the TS AST. That's already on the way:

typescript-eslint/typescript-eslint#1436
typescript-eslint/typescript-eslint#1465
babel/babel#10981

I think we should wait, instead of complicating and adding specific @types logic in here.

@viceice
Copy link

viceice commented Feb 28, 2020

I see the same error for type-fest. Using the following as workaround.

{
  ...,
  settings: {
    'import/internal-regex': '^type\\-fest$',
  },
  ...
}

@filipsuk
Copy link

Is there a way to suppress this error when using new TS syntax import type ...? Or any other workaround apart from naming all the modules in import/internal-regex?

import type { APIGatewayEvent, APIGatewayEventRequestContext } from 'aws-lambda';

causes ESLint: 'aws-lambda' should be listed in the project's dependencies. Run 'npm i -S aws-lambda' to add it(import/no-extraneous-dependencies)

in my devDependencies

"@types/aws-lambda": "8.10.40",

@fernandopasik
Copy link
Contributor

Typescript 3.8 is out, and looks like the situation of using import type is still reporting an error

@ljharb
Copy link
Member

ljharb commented Jun 12, 2020

Please file a PR with failing test cases; that makes things much easier to fix.

@fernandopasik
Copy link
Contributor

Looking a bit closer to this issue I found that the node at that point doesn't have a importKind, but it is in it's parent

{
  type: 'Literal',
  raw: "'type-fest'",
  value: 'type-fest',
  range: [ 33, 44 ],
  loc: { start: { line: 1, column: 33 }, end: { line: 1, column: 44 } },
  parent: {
    type: 'ImportDeclaration',
    source: [Circular *1],
    specifiers: [ [Object] ],
    importKind: 'type',
    range: [ 0, 45 ],
    loc: { start: [Object], end: [Object] },
    parent: {
      type: 'Program',
      body: [Array],
      sourceType: 'module',
      range: [Array],
      loc: [Object],
      tokens: [Array],
      comments: [],
      parent: null
    }
  }
}

@ljharb could it be that in the rule it would need

// Do not report when importing types 
 if (node.importKind === 'type' || node.parent.importKind === 'type') { 
   return 
 } 

to be compatible with the typescript import type ?

@ljharb
Copy link
Member

ljharb commented Jun 12, 2020

That very well might be exactly what's needed (but probably would be needed in dozens of places). Want to make a PR with some tests? :-D

@fernandopasik
Copy link
Contributor

Created the PR and added tests.

@vamcs
Copy link

vamcs commented Aug 8, 2020

❓ is this fix released already?

@ljharb
Copy link
Member

ljharb commented Aug 8, 2020

@vamcs yes - if you click on the commit link above, you'll see it's included in v2.22.0.

@vamcs

This comment has been minimized.

@ljharb

This comment has been minimized.

@vamcs

This comment has been minimized.

@samtgarson
Copy link

Hello! I think this is the same issue, but shout if it's separate.. I'm still getting this issue on version 2.22.1.

See this GitHub Action build: https://github.com/samtgarson/hooks/runs/1862888533?check_suite_focus=true

Specifically I'm seeing the plugin give errors for no-extraneous-dependencies for types from @vercel/node.

Interestingly, it's ignoring the devDependencies configuration and erroring on test files too (it's also complaining about no-unused-vars, which is a separate issue but suggests to me these types are not being parsed as types correctly).

@ljharb
Copy link
Member

ljharb commented Feb 9, 2021

@samtgarson the .spec.js in your eslint config only allows dev deps in test files, and it's erroring in lib/endpoint.ts, which isn't a test file, so the config seems correct.

As for the imports themselves - can you use import type for the types? My assumption is that the typescript eslint parser isn't recognizing those as type imports. It's also possible that your issue is fixed on master but unreleased.

@samtgarson
Copy link

samtgarson commented Feb 9, 2021

@samtgarson the .spec.js in your eslint config only allows dev deps in test files, and it's erroring in lib/endpoint.ts, which isn't a test file, so the config seems correct.

It's also erroring in hooks/api/kindle/_test/index.spec.js.

As for the imports themselves - can you use import type for the types? My assumption is that the typescript eslint parser isn't recognizing those as type imports.

This issue is specifically about not using import type, which apparently was already supported, but for confirmation import type does work. I don't think this would be a suitable fix if you were importing both types and values from a library.

It's also possible that your issue is fixed on master but unreleased.

I'll pull master and check. If not, does this warrant reopening the issue?

@samtgarson
Copy link

samtgarson commented Feb 9, 2021

@ljharb can confirm this issue exists on my repo when using master. Unfortunately I don't have time right now to look at creating a failing test case, hopefully soon, but is the reproduction on that repo of any use?

I'm not sure the relevance of this but after a quick dig, it appears the @vercel/node imports are coming in with importKind == "value", even with import type.

@ljharb
Copy link
Member

ljharb commented Feb 9, 2021

If that's the case, then it's coming from the TS eslint parser, not from this plugin - can you file an issue there and link it here?

@AndyOGo
Copy link
Contributor

AndyOGo commented Mar 14, 2023

In line type imports do not work.

// works
import type { Foo } from "types-package";

// doesn't work yet
import { type Foo } from "types-package".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment