Repository: import-js/eslint-plugin-import
Pull request #2735 (2023-03-14 22:12:48)

[Fix] `no-extraneous-dependencies`/TypeScript: do not error when importing inline type from dev dependencies
fixes https://github.com/import-js/eslint-plugin-import/issues/1618

This PR is to avoid error `should be listed in the project's dependencies, not devDependencies.` when only importing inline typescript types


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bbfaa0fb..fe7f6771 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
 - [`no-duplicates`]: remove duplicate identifiers in duplicate imports ([#2577], thanks [@joe-matsec])
 - [`consistent-type-specifier-style`]: fix accidental removal of comma in certain cases ([#2754], thanks [@bradzacher])
 - [Perf] `ExportMap`: Improve `ExportMap.for` performance on larger codebases ([#2756], thanks [@leipert])
+- [`no-extraneous-dependencies`]/TypeScript: do not error when importing inline type from dev dependencies ([#1820], thanks [@andyogo])
 
 ### Changed
 - [Docs] [`no-duplicates`]: fix example schema ([#2684], thanks [@simmo])
@@ -1070,6 +1071,7 @@ for info on changes for earlier releases.
 [#2756]: https://github.com/import-js/eslint-plugin-import/pull/2756
 [#2754]: https://github.com/import-js/eslint-plugin-import/pull/2754
 [#2748]: https://github.com/import-js/eslint-plugin-import/pull/2748
+[#2735]: https://github.com/import-js/eslint-plugin-import/pull/2735
 [#2699]: https://github.com/import-js/eslint-plugin-import/pull/2699
 [#2664]: https://github.com/import-js/eslint-plugin-import/pull/2664
 [#2613]: https://github.com/import-js/eslint-plugin-import/pull/2613
@@ -1625,6 +1627,7 @@ for info on changes for earlier releases.
 [@alexgorbatchev]: https://github.com/alexgorbatchev
 [@andreubotella]: https://github.com/andreubotella
 [@AndrewLeedham]: https://github.com/AndrewLeedham
+[@andyogo]: https://github.com/andyogo
 [@aravindet]: https://github.com/aravindet
 [@arvigeus]: https://github.com/arvigeus
 [@asapach]: https://github.com/asapach
diff --git a/docs/rules/no-extraneous-dependencies.md b/docs/rules/no-extraneous-dependencies.md
index 68cd4b15..660875d1 100644
--- a/docs/rules/no-extraneous-dependencies.md
+++ b/docs/rules/no-extraneous-dependencies.md
@@ -12,6 +12,7 @@ Modules have to be installed for this rule to work.
 This rule supports the following options:
 
 `devDependencies`: If set to `false`, then the rule will show an error when `devDependencies` are imported. Defaults to `true`.
+Type imports are ignored by default.
 
 `optionalDependencies`: If set to `false`, then the rule will show an error when `optionalDependencies` are imported. Defaults to `true`.
 
diff --git a/src/rules/no-extraneous-dependencies.js b/src/rules/no-extraneous-dependencies.js
index d6437c2f..a149ca65 100644
--- a/src/rules/no-extraneous-dependencies.js
+++ b/src/rules/no-extraneous-dependencies.js
@@ -178,7 +178,12 @@ function reportIfMissing(context, deps, depsOptions, node, name) {
   // Do not report when importing types unless option is enabled
   if (
     !depsOptions.verifyTypeImports &&
-    (node.importKind === 'type' || node.importKind === 'typeof')
+    (node.importKind === 'type' || node.importKind === 'typeof' ||
+    (
+      Array.isArray(node.specifiers) &&
+      node.specifiers.length &&
+      node.specifiers.every((specifier) => specifier.importKind === 'type' || specifier.importKind === 'typeof'))
+    )
   ) {
     return;
   }


Test patch:
diff --git a/tests/src/rules/no-extraneous-dependencies.js b/tests/src/rules/no-extraneous-dependencies.js
index 8815f63c..84aa8bb3 100644
--- a/tests/src/rules/no-extraneous-dependencies.js
+++ b/tests/src/rules/no-extraneous-dependencies.js
@@ -438,7 +438,7 @@ describe('TypeScript', () => {
 
           test(Object.assign({
             code: 'import type T from "a";',
-            options: [{ 
+            options: [{
               packageDir: packageDirWithTypescriptDevDependencies,
               devDependencies: false,
               includeTypes: true,
@@ -464,6 +464,16 @@ typescriptRuleTester.run('no-extraneous-dependencies typescript type imports', r
       filename: testFilePath('./no-unused-modules/typescript/file-ts-a.ts'),
       parser: parsers.BABEL_OLD,
     }),
+    test({
+      code: 'import { type MyType } from "not-a-dependency";',
+      filename: testFilePath('./no-unused-modules/typescript/file-ts-a.ts'),
+      parser: parsers.BABEL_OLD,
+    }),
+    test({
+      code: 'import { type MyType, type OtherType } from "not-a-dependency";',
+      filename: testFilePath('./no-unused-modules/typescript/file-ts-a.ts'),
+      parser: parsers.BABEL_OLD,
+    }),
   ],
   invalid: [
     test({
@@ -476,7 +486,7 @@ typescriptRuleTester.run('no-extraneous-dependencies typescript type imports', r
       }],
     }),
     test({
-      code: `import type { Foo } from 'not-a-dependency'`,
+      code: `import type { Foo } from 'not-a-dependency';`,
       options: [{ includeTypes: true }],
       filename: testFilePath('./no-unused-modules/typescript/file-ts-a.ts'),
       parser: parsers.BABEL_OLD,
@@ -484,5 +494,21 @@ typescriptRuleTester.run('no-extraneous-dependencies typescript type imports', r
         message: `'not-a-dependency' should be listed in the project's dependencies. Run 'npm i -S not-a-dependency' to add it`,
       }],
     }),
+    test({
+      code: 'import Foo, { type MyType } from "not-a-dependency";',
+      filename: testFilePath('./no-unused-modules/typescript/file-ts-a.ts'),
+      parser: parsers.BABEL_OLD,
+      errors: [{
+        message: `'not-a-dependency' should be listed in the project's dependencies. Run 'npm i -S not-a-dependency' to add it`,
+      }],
+    }),
+    test({
+      code: 'import { type MyType, Foo } from "not-a-dependency";',
+      filename: testFilePath('./no-unused-modules/typescript/file-ts-a.ts'),
+      parser: parsers.BABEL_OLD,
+      errors: [{
+        message: `'not-a-dependency' should be listed in the project's dependencies. Run 'npm i -S not-a-dependency' to add it`,
+      }],
+    }),
   ],
 });