Prevent deduplication of imports with same `from` and `name`, but different `type`
enhancement
### Describe the feature
When "resolving" imports to format them, they are first deduped with the `dedupeImports` function. Currently, the main criteria to decide whether to dedupe are the `name` and `from` properties of an `Import`. However, with TypeScript, it is possible and valid to have two exports in the same module with the same identifier if one is for the value and other for the type, which is what enables using class identifiers as both values (`new SomeClass()`) and types (`(p: SomeClass) => void`). Therefore, the following imports should not be deduped to account for this use case:
```js
[{
name: identifier,
from: specifier
},{
name: identifier,
from: specifier,
type: true
}]
```
### Example
Here is a [demo](https://stackblitz.com/edit/stackblitz-starters-2vc8jzh2?file=index.js&view=editor) using `generateTypeDeclarations` with an imports array like the one shown above. To test run `node index.js`. Due to deduplication, the output depends on the order of the imports. Possible outputs are:
```
export {}
declare global {
const Test: typeof import('./module').Test
}
```
```
export {}
declare global {
}
// for type re-export
declare global {
// @ts-ignore
export type { Test } from './module'
import('./module')
}
```
If these are used to create `d.ts` files, the `Test` identifier will only be usable as either a value (first case) or a type (second case), but not both.
### Workaround
Imports support a `declarationType: 'class'` property, which could be used to obtain the desired output. However, this property does not seem designed to solve this particular issue; using `declarationType: 'class'` simply [exempts an import from being deduplicated](https://github.com/unjs/unimport/blob/v6.0.1/src/utils.ts#L120), so both import entries are still required. Two additional issues with this approach are:
- (truly) duplicate imports with `declarationType: 'class'` are not deduplicated.
- it does not work well with inline presets, where a list (array) of export names is provided.
### More motivation
Exported values and types with the same identifiers are not exclusive to the `export class` syntax. For instance, in TypeScript a class' type can be customized with the following pattern:
```ts
class TestImpl {}
interface TestConstructor {}
interface TestInstance {}
export type Test = TestInstance
export const Test: TestConstructor = TestImpl as any
```
Therefore, I think the most reliable solution would be for the `dedupeImports` function to support not deduping imports that are "complementary", i.e., same module and identifier (`from` and `name`), but different scope (`type`).
---
I am planning to submit a PR refactoring `dedupeImports` to address this.
### Additional information
- [x] Would you be willing to help implement this feature?
0 条评论