Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with subclasses #6

Open
Valandur opened this issue Feb 16, 2021 · 2 comments
Open

Issue with subclasses #6

Valandur opened this issue Feb 16, 2021 · 2 comments

Comments

@Valandur
Copy link

Hi, thanks for the great library 👍

I have a question about the subclasses with different events example that you provided in the readme:

The example works when calling the events from outside the class, but not from within the class itself. Specifically, if I alter the example to be as follows:

class Animal<E extends ListenerSignature<E> = ListenerSignature<unknown>> extends TypedEmitter<{ spawn: () => void } & E> {
	public constructor() {
		super();
	}

	private doSpawn() {
		this.emit('spawn');
	}
}

class Frog<E extends ListenerSignature<E>> extends Animal<{ jump: (testing: boolean) => void } & E> {}
class Bird<E extends ListenerSignature<E>> extends Animal<{ fly: () => void } & E> {}

Then the compiler fails at the this.emit('spawn'); line with the error: Argument of type '[]' is not assignable to parameter of type 'Parameters<({ spawn: () => void; } & E)["spawn"]>'.

I'm assuming this is because of some constraint that can't be applied, but I can't seem to wrap my head around it. Is there any way to solve this?

@scottpageindysoft
Copy link

scottpageindysoft commented Mar 20, 2021

I finally worked around this issue by following how FeathersJS extends its ServiceTypes interface;
I failed to realize that we can extend interfaces from different files using the module syntax, declare module './declaration-ts-file', within the file of the class you want to extend events.

To make this work, follow these steps:

  1. Create a TS file to store the base events (i.e. ServiceEvents.ts)
  2. In that base events file add your events interface (i.e. export interface ServiceEvents { someEvent: () => void; })
  3. In your base class file, extends TypedEmitter<ServiceEvents> as you normally would
  4. In your child class file, extend the base class
  5. In that same child class file, declare a module with the filename of the base events interface as follows...

declare module './ServiceEvents' { interface ServiceEvents { newEvent: (data: string) => void; } }

You will now have a strongly typed "newEvent" for the child class and observe that other child classes will not have that new event, as expected.

Notice that I created the interfaces and classes in separate files as to eliminate any possibility for a collision with another declare module './ServiceEvents' declaration.

Enjoy.

@scottpageindysoft
Copy link

scottpageindysoft commented Mar 20, 2021

Scratch my previous.
I tested it in my module, published the module, and everything worked okay with 2 files.
Beyond that, it spews the events into other types. It was probably doing that with 2 files, but I didn't catch it.

So, you could use what I stated previously, however you will end up with code bleed all over.

I have another solution that I've been using for a few months, but it's hackish.
I'll post it here when I get a minute. Basically you'll need to create your own on and once overrides for the emitter with new generic type defs. From what I recall I also had to wrap another class that extended EventEmitter.

chanced added a commit to chanced/classy-store that referenced this issue Aug 2, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants