egoist / tsup

The simplest and fastest way to bundle your TypeScript libraries.
https://tsup.egoist.dev
MIT License
8.48k stars 209 forks source link

Issue with declaration merging and `export *` namespaces #1045

Open Retsam opened 7 months ago

Retsam commented 7 months ago

We're running into an issue trying to support declaration merging in our library, while exporting the interface behind a export * from "file" as Namespace. The code works when the declarations are generated via tsc but not when generated via tsup.

I've built a reproduction here: https://github.com/Retsam/tsup-declaration-merge-issue-repro

And here's a TS Bug Workbench with just the generated code: Bug Workbench


The relevant code is:

lib/index.ts:

export * as Mod from "./mod";

lib/mod.ts

// This is meant for declaration merging
export interface EventMap {}

export function addListener<E extends keyof EventMap>(_event: E, _handle: (payload: EventMap[E]) => void) {}

app/index.ts

import { Mod } from "lib";

declare module "lib" {
  namespace Mod {
    interface EventMap {
      myEvent: string;
    }
  }
}

Mod.addListener("myEvent", (val) => {
  console.log(val.toUpperCase());
});

The generated code is:

interface EventMap {}
declare function addListener<E extends keyof EventMap>(_event: E, _handle: (payload: EventMap[E]) => void): void;

type mod_EventMap = EventMap;
declare const mod_addListener: typeof addListener;
declare namespace mod {
  export { type mod_EventMap as EventMap, mod_addListener as addListener };
}

export { mod as Mod };

From playing with this, it seems like the declaration merge is modfying the interface inside the namespace, but somehow that's not the same as the one outside the namespace. (I'm not 100% sure this isn't a TS bug) I found that something I could do to 'fix' it (via manually editing the .d.ts file) was:

 interface EventMap {}
-declare function addListener<E extends keyof EventMap>(
+declare function addListener<E extends keyof mod.EventMap>(
     _event: E, 
-    _handle: (payload: EventMap[E]) => void
+    _handle: (payload: mod.EventMap[E]) => void
 ): void;

Upvote & Fund

Fund with Polar