Search code examples
typescripttypescript-generics

Augment/replace union type from typescript library


I have a library that is used by client apps within my organization. I'm moving some shared code into the library. That shared code is an event publication method called publishEvent. publishEvent takes an object and an event name. The name could be a string, but I don't want that. In order to support intellisense in the application code I want it to be a union, but that union can only really be defined by the application.

So the signature is something like:

publishEvent(event: unknown, eventName: EventName): Promise<void>

The library needs to declare the type because it needs it in order to support the publishEvent signature, but only the application can actually know the set of strings that are valid event names. I've tried several approaches including namespaces, module augmentation, etc, and I can't figure out an approach that will actually work.

Keeping in mind the following goals:

  1. Common code living in the shared library
  2. EventName definitions being located in the application code
  3. Intellisense/Compile-time support in the application code using the union defined in the application -- NOT the library.

Is there any approach that will work for me? This doesn't feel like something generics will help with, but maybe I'm wrong there.


Solution

  • Got it. The trick is to have the library code use an ambient types from a d.ts file (probably nested under a namespace, but you do you), and then have the application code override that type in their own d.ts file.

    Library:

    // library-namespace.d.ts
    namespace MyLibrary {
      type EventName: string; // we don't care in the lib.  String is fine.
    }
    

    Application:

    // library-overrides.d.ts
    namespace MyLibrary {
      type EventName: 'This' | 'That'; // app-specific event types
    }