strict-event-emitter-types icon indicating copy to clipboard operation
strict-event-emitter-types copied to clipboard

Class support?

Open SrZorro opened this issue 6 years ago • 9 comments

I'm trying to use this library to add types to my class that extends from EventEmitter, but I can't find a way to make it work with my example:

import StrictEventEmitter from "strict-event-emitter-types";
import { EventEmitter } from "events";

interface IEvents {
    onValueSended: string;
    ready: void;
}

//    [ts] Class 'MyClass' incorrectly
//    implements interface 'IEvents'.
//    Property 'onValueSended' is missing     [ts] Generic type 'StrictEventEmitter'
//    in type 'MyClass'.                      requires between 2 and 5 type arguments.
//    ↓                                       ↓
class MyClass extends EventEmitter implements StrictEventEmitter<EventEmitter IEvents> {
    constructor() {
        super();
        // Some long work...
        this.emit("ready");
    }
    sendValue() {
        this.emit("onValueSended", "Hello!");
    }
}

const myClass = new MyClass();
myClass.on("onValueSended", x => x);
myClass.sendValue(); // ← [ts] Property 'sendValue' does not exist on type 'MyClass'.
myClass.on("ready", () => {/* Do stuff... */ });

Also, there is a way to make it work with computed properties? Lets say I want to have an event called something like

interface IEvents {
    /^action_.+/: void;
    init: number;
}
/* class MyClass etc... */
myClass.on("action_jump", () => {})
myClass.on("action_dance", (x) => {}) //Error, no payload
myClass.on(/^action_.+/, () => {}) //Match all action events
myClass.on("jump_action", () => {}) //Error
myClass.on("action_", () => {}) //Error
myClass.on("init", (x) => {})

I supose this last one is related with https://github.com/Microsoft/TypeScript/issues/6579 and can't be fixed by this library.

SrZorro avatar Jun 25 '18 16:06 SrZorro

@SrZorro I solved it like this:

const VmEventsEmitter: { new (): StrictEventEmitter<EventEmitter, IVmEvents> } = EventEmitter as any; // ugly AF any cast was required b/c i think i had old nodejs typings. That should not be important

export class VM extends VmEventsEmitter { 
    // ...
}

It's kinda ulgy but it works 😆

krzkaczor avatar Jul 08 '18 14:07 krzkaczor

@krzkaczor what version of node are you running? I can probably tweak the types so they work for that version.

As that's the only way I've found thus far to teach class methods about the stricter types, I'll add it to the docs!

bterlson avatar Jul 20 '18 23:07 bterlson

@bterlson typings are for 10.3.4

"@types/node@^10.3.4":
  version "10.3.4"

Thanks!

krzkaczor avatar Jul 21 '18 14:07 krzkaczor

I added an example of using this with classes (similar to @krzkaczor's solution). I'm not aware of a better way...

I'll leave this open so I remember to dig into the Node 10.3.4 typings.

bterlson avatar Sep 10 '18 17:09 bterlson

So, how should it look like if i have IEvents with generic types? For example:

interface IEvents<Value> {
    onValueSended: Value;
}

class MyClass<Value> extends (EventEmitter as { new(): StrictEventEmitter<EventEmitter, IEvents<Value>> }) {
  ...
}

It throws error: Error:(69, 45) TS2562: Base class expressions cannot reference class type parameters.

sywka avatar Oct 05 '18 15:10 sywka

@sywka https://github.com/ethereum-ts/evm-ts/blob/master/lib/VM.ts#L21

krzkaczor avatar Oct 07 '18 07:10 krzkaczor

@krzkaczor I understand, but i need exactly generic for IEvents<Value> which is taken from MyClass<Value> and apparently this is impossible.

sywka avatar Oct 08 '18 11:10 sywka

Why not add a helper to do this?

Eg.

function createStrictEventEmitterClass<T>() {
    const TypedEmitter: {
        new (): StrictEventEmitter<EventEmitter, T>;
    } = EventEmitter as any;

    return TypedEmitter;
}

export class MyEventEmitter extends createStrictEventEmitterClass<MyEvents>() {

}

I can send a PR if you want this.

esamattis avatar Oct 09 '18 12:10 esamattis

@bterlson I would really like to see this added to your library.

Is someone working on this? @esamattis maybe? Or should I create a PR, and how do you want it structered in your Type only library?

svrooij avatar Apr 15 '20 12:04 svrooij