Augmentreplace union type from typescript library - Stack Overflow

admin2025-04-29  1

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.

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.

Share Improve this question asked Jan 6 at 22:46 Mike SnareMike Snare 4231 gold badge5 silver badges18 bronze badges 3
  • It's hard to demonstrate multi-file things. My suggestion would look like either this bug workbench link or this playground link, but note that the bug workbench doesn't have great IntelliSense while the playground doesn't support multi-file so I need to use namespaces instead of modules. – jcalz Commented Jan 7 at 15:21
  • (see prev comment) That being said, the approach would be to have the library export an Events interface, and use type EventName = keyof Events. Then users could import your library and use module augmentation to merge their own events in. You can't augment unions, but you can augment interfaces, so that's why I'm using this approach. Does that fully address the question? If so I'll write an answer; if not, what's missing? – jcalz Commented Jan 7 at 15:21
  • 1 Thanks @jcalz. I eventually got this solved as in my answer below but I appreciate the help. – Mike Snare Commented Jan 8 at 16:15
Add a comment  | 

1 Answer 1

Reset to default 0

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
}
转载请注明原文地址:http://anycun.com/QandA/1745940644a91415.html