timocov/dts-bundle-generator

Sub-Paths in imports and renamed imports generate invalid output

Closed this issue · 5 comments

Bug report
When trying to bundle the declaration files for a file with renamed imports and/or imports with sub-paths, the generated declaration file becomes invalid.

Steps to reproduce

  1. Create a new repo
  2. npm init
  3. npm i typescript dts-bundle-generator alcalzone-shared
  4. Create tsconfig.json:
{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "declaration": true,
    "strict": true,
    "esModuleInterop": true
  }
}
  1. create a.ts:
import { Overwrite } from "alcalzone-shared/types";
import { Overwrite as Merge } from "alcalzone-shared/types";

export type Foo = Overwrite<{a: number}, {b: number}>;
export type Bar = Merge<{a: number}, {b: number}>;
  1. node_modules\.bin\dts-bundle-generator -o index.d.ts a.ts

Expected output

import { Overwrite, Overwrite as Merge } from 'alcalzone-shared/types';

export declare type Foo = Overwrite<{
	a: number;
}, {
	b: number;
}>;
export declare type Bar = Merge<{
	a: number;
}, {
	b: number;
}>;

Actual output

import { Overwrite } from 'alcalzone-shared';

export declare type Foo = Overwrite<{
	a: number;
}, {
	b: number;
}>;
export declare type Bar = Merge<{
	a: number;
}, {
	b: number;
}>;

The renamed import for Merge is missing and the import path is wrong (missing /types).

Hi,

it is a known limitation.

As workaround you can try to re-export Merge as the following (if you actually need to have renaming):

import { Override as Merge } from 'alcalzone-shared/types';

// do your stuff with Merge

export { Override as Merge } from 'alcalzone-shared/types';

I don't know if there a way to fix it in right way. I can try to find a solution, but I cannot tell you for sure when it will be implemented (if there is such solution).

Hm, it seems that my workaround may not work 🙁

Okay, I can get along without renaming, but what about /types? That part simply gets dropped in the compiled output.

It is a good question.

On the one side, if the package provides d.ts file for its entry file (main/index), you need to use it instead of importing from some internal directory/file.

On the other hand, some packages bundle (or just have created separate "entry" file) their parts in separate entries and this is documented (and actually correct) way to import that part.

And finally, we have a tool which does not know what imports are documented and what aren't. But as far import from main/index file is common way to import other package, dts-bundle-generator assumes that it is only one correct way to import the package (just main file).

When dts-bundle-generator meets some symbol, it computes the name of the package where it declared (to import it afterwards). Yes, we know the file where that symbol is declared (actually, we have an array of the files because the same symbol can be declared in multiple files - for example due declaration merging), but we don't know is that file from "public" API or not. Somebody should tell this information for the tool. Currently there is no such option.

It is possible that dts-bundle-generator should save the original import's paths. But what if you have import the same symbol in different way (from main file and from package-name/part)? What we should do in this case? If we just leave they as-is, we'll get compile error about duplicate identifiers. But if we decide to leave only one, then which one?

As you can see, there is a lot of pitfalls and for now I would suggest you import from main file and export all types without renaming (or "scoping in a namespace") in the main file (e.g. export * from './types';) when it is possible.

Perhaps we can fix it in the same way as in #59 (comment).