eslint-plugin-import icon indicating copy to clipboard operation
eslint-plugin-import copied to clipboard

feature request: add ignore options for `import/no-duplicates`

Open JounQin opened this issue 5 years ago • 36 comments

When using TypeScript with date-fns, it only has one bundled typings.d.ts, so eslint-import-resolver-ts will resolve all modules to it.

But they are not all exported from date-fns, what means date-fns and date-fns/locale are different.

So we should allow this case by whitelist.

JounQin avatar Sep 17 '19 15:09 JounQin

This seems like an inherent flaw in resolving a module to a d.ts file that might represent multiple files. I don’t think forcing an allowlist is an elegant solution; I’d prefer to find a better one.

ljharb avatar Sep 17 '19 15:09 ljharb

If we do have a better one, that will be greater.

JounQin avatar Sep 17 '19 15:09 JounQin

@ljharb Any news on this. If we don't have a better solution, an option for whitelist maybe considered?

JounQin avatar Feb 21 '21 03:02 JounQin

Rereading the OP, it kind of seems like it’s just a bug in date-fns’ typings file?

ljharb avatar Feb 21 '21 04:02 ljharb

Why do you think it's a bug of date-fns? It's valid usage of .d.ts files.

JounQin avatar Feb 21 '21 05:02 JounQin

But they are not all exported from date-fns, what means date-fns and date-fns/locale are different.

ljharb avatar Feb 21 '21 14:02 ljharb

.d.ts are fine to be declared in one file for multiple sources. It valid and TypeScript itself doesn't complain. So it's just a choice.

JounQin avatar Feb 21 '21 14:02 JounQin

If the types in date-fns are correct, then eslint-import-resolver-ts (eslint-import-resolver-typescript is the one i recommend, incidentally) should be resolving them properly.

I'm still confused what the issue is. Are you saying that because date-fns and date-fns/locale resolve to the same type file, they're considered as duplicate imports?

ljharb avatar Feb 21 '21 14:02 ljharb

import * from 'date-fns'
import * from 'date-fns/locale'

The above import statements both resolves a same typings.d.ts which include

declare module 'date-fns' {
  // ...
}

declare module 'date-fns/locale' {
  // ...
}

JounQin avatar Feb 21 '21 15:02 JounQin

Are you saying that because date-fns and date-fns/locale resolve to the same type file, they're considered as duplicate imports?

Yes, that's the point.

JounQin avatar Feb 21 '21 15:02 JounQin

It doesn’t seem right to me that they should resolve to the location of their types, so that seems like something that should be fixed in the resolver.

ljharb avatar Feb 21 '21 16:02 ljharb

What's the problem of the resolver? We may import types from the pkg, there is no types in .js sources, so .d.ts files are preferred.

JounQin avatar Feb 22 '21 00:02 JounQin

Yeah, i can see the difficulty. I’m not sure how we’d solve this properly. An exclude list seems like a workaround.

ljharb avatar Feb 22 '21 01:02 ljharb

An exclude list seems like a workaround.

So is this accepted? I can raise a PR if so.

JounQin avatar Feb 22 '21 03:02 JounQin

Given that most packages do the right thing, and don't ship types directly but rather use DT, and given that this is a potential problem with any package that chooses to conflate its API's semver with the semver of its types, I'd prefer to not add an exclude list and instead seek a true fix.

ljharb avatar Feb 22 '21 04:02 ljharb

So we need to support resolve .d.ts with original .js source at the same time, right?

JounQin avatar Feb 22 '21 05:02 JounQin

I think that is the challenge, yes.

ljharb avatar Feb 23 '21 19:02 ljharb

Hi, we have the issue where --fix merge both:

import { format } from 'date-fns';
import fr from 'date-fns/locale/fr';

is merged into

import fr, { format } from 'date-fns';

Is there a way to avoid this since the last msg is from more than a year ago? Right now we have to disable eslint on it which doesn't really look like a solution :/

wcastand avatar Oct 25 '22 15:10 wcastand

Hi @wcastand,

our workaround for this, until its solved, looks like this:

/* eslint-disable import/no-duplicates */
import formatDate from 'date-fns/format'
import enGB from 'date-fns/locale/en-GB'
import de from 'date-fns/locale/de'
/* eslint-enable import/no-duplicates */

I hope this helps.

natterstefan avatar Oct 25 '22 18:10 natterstefan

yeah we went with a ignore next line on each line but it's not really a solution to me. thanks for sharing still :)

wcastand avatar Oct 27 '22 08:10 wcastand

This was my temporary solution:

import { differenceInDays, format, startOfDay, startOfToday } from "date-fns";
import * as locale from "date-fns/locale";

...

const { ptBR } = locale;

manfrinmm avatar Nov 29 '22 22:11 manfrinmm

@manfrinmm import * as locale from "date-fns/locale" imports all locales available in date-fns, increasing the build size.

that's my temporary solution:

// locale/dateFns.ts
import ptBRLocale from 'date-fns/locale/pt-BR';

export { ptBRLocale };

// other files
import { ptBRLocale } from './locale/dateFns';

lucasdu4rte avatar Dec 07 '22 13:12 lucasdu4rte

at this rate especially because of this bug I think using something that utilizes the typescript language server may be more prudent (e.g. prettier-plugin-organize-imports). I just got dinged by this when I was setting up the ESLint rules for my monorepo

trajano avatar Jan 22 '23 18:01 trajano

Another simple use-case:

import format from 'date-fns/format';
import differenceInHours from 'date-fns/differenceInHours';
import orderBy from 'lodash/orderBy';
import get from 'lodash/get';
image
'.../node_modules/date-fns/typings.d.ts' imported multiple times

Would love to have an options to exclude some packages or patterns from the check

alexilyaev avatar May 04 '23 12:05 alexilyaev

A temporary workaround can be to use eslint-plugin-local and define a custom post-processor:

plugins: ['local'],
processor: 'local/suppress',

Then, to create a .eslintplugin.js file in the root of the project with the following content:

module.exports = {
  processors: {
    suppress: {
      postprocess: (messages) => {
        const [message] = messages.map((violations) =>
          violations.filter(
            (violation) =>
              !violation.message.endsWith(
                "date-fns/typings.d.ts' imported multiple times."
              )
          )
        )
        return message
      }
    }
  }
}

But a proper support of it is still highly desirable. Either with an array of excludes, or a proper support on the resolver level.

mvshmakov avatar Jun 25 '23 14:06 mvshmakov

Same thing happens with svelte:

  import { onMount } from "svelte"
  import { slide } from "svelte/transition"

will be fixed to yield

  import { onMount, slide } from "svelte"

EmCeeEs avatar Nov 01 '23 19:11 EmCeeEs

Same problem here. Would love a resolution!

This can probably be paired with eslint-import-resolver-typescript#197 as a 'refactor the way .d.ts modules are handled' issue

ShadiestGoat avatar Nov 20 '23 04:11 ShadiestGoat

This can probably be paired with https://github.com/import-js/eslint-import-resolver-typescript/issues/197 as a 'refactor the way .d.ts modules are handled' issue

You will meet this issue more often if custom .d.ts with declare is supported.

JounQin avatar Nov 20 '23 04:11 JounQin

This can probably be paired with https://github.com/import-js/eslint-import-resolver-typescript/issues/197 as a 'refactor the way .d.ts modules are handled' issue

You will meet this issue more often if custom .d.ts with declare is supported.

Not if its properly supported

ShadiestGoat avatar Nov 20 '23 11:11 ShadiestGoat

I may do some prototypes on https://github.com/un-es/eslint-plugin-i

JounQin avatar Jan 17 '24 16:01 JounQin