Skip to content

[import/no-duplicates] issues with default and namespace type imports #3195

Open
@robyoder

Description

@robyoder

v2.32.0

I've seen some issues filed about no-duplicates and type imports, but they appear different from what I'm currently seeing in version 2.32.0.

no-duplicates rule code in question
    function getImportMap(n) {
      if (!moduleMaps.has(n.parent)) {
        moduleMaps.set(n.parent, /** @type {typeof moduleMaps} */ {
          imported: new Map(),
          nsImported: new Map(),
          defaultTypesImported: new Map(),
          namedTypesImported: new Map(),
        });
      }
      const map = moduleMaps.get(n.parent);
      if (!preferInline && n.importKind === 'type') {
        return n.specifiers.length > 0 && n.specifiers[0].type === 'ImportDefaultSpecifier' ? map.defaultTypesImported : map.namedTypesImported;
      }
      if (!preferInline && n.specifiers.some((spec) => spec.importKind === 'type')) {
        return map.namedTypesImported;
      }

      return hasNamespace(n) ? map.nsImported : map.imported;
    }

1. Namespace type imports are grouped with named type imports when prefer-inline is off.

With prefer-inline off, an error is shown for the following code, but the error disappears when turning on prefer-inline.

import type * as React from "react";
import { type ReactElement } from "react";

If anything, that would be backwards, but really, these two lines can never be combined. The problem comes from this block in the rule code:

      if (!preferInline && n.importKind === 'type') {
        return n.specifiers.length > 0 && n.specifiers[0].type === 'ImportDefaultSpecifier' ? map.defaultTypesImported : map.namedTypesImported;
      }

This block says if we're dealing with a type import, it's either a default import or a named import, but that's not true — it could also be a namespace import, which similarly can't be combined with named imports.

2. Default type imports are grouped with named type imports when prefer-inline is on

With prefer-inline on, an error is shown for the following code:

import type React from "react";
import { type ReactElement } from "react";

But attempting to combine them into a single line yields the following TypeScript error:

A type-only import can specify a default import or named bindings, but not both.

This problem is caused by this line from the rule source:

      return hasNamespace(n) ? map.nsImported : map.imported;

It says if prefer-inline is on (meaning previous if blocks are skipped), the only two groups are namespace imports and not, but this doesn't work for default type imports, which must be separated from named type imports.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions