Typed Events with TypeScript and EventEmitter

I am trying to add strongly typed events to an EventEmitter like system using TypeScript.

We are currently defining our types, for example:

interface TypedMsg<Name, T> {
  messageType: Name;
  message: T;
}

type TypedMsgFoo = TypedMsg<'FOO', string>;
type TypedMsgBar = TypedMsg<'BAR', number>;
type EitherFooOrBar = TypedMsgFoo | TypedMsgBar;

      

I would like to define an interface like:

interface EventHandler<T extends TypedMsg<any, any> {
  on: (messageType: T.messageType, handler: (T.message) => void) => void;
}

      

But Typescript doesn't support extracting type subtypes T.messageType

. Is there any other way to do this?

The ultimate goal would be to define properly typed handlers with:

class FooBarHandler implements EventHandler<EitherFooOrBar> {
  on(messageType: EitherFooOrBar.messageType) {...}
}

      

+3


source to share


1 answer


Typescript supports extracting member types, just the syntax is a bit fancy - it's called the indexed accessor type operator

interface TypedMsg<Name, T> {
  messageType: Name;
  message: T;
}

type TypedMsgFoo = TypedMsg<'FOO', string>;
type TypedMsgBar = TypedMsg<'BAR', number>;
type EitherFooOrBar = TypedMsgFoo | TypedMsgBar;

interface EventHandler<T extends TypedMsg<{}, {}>> {
  on: (messageType: T['messageType'], handler: (m: T['message']) => void) => void;
}

class FooBarHandler implements EventHandler<EitherFooOrBar> {
    on(
        messageType: EitherFooOrBar['messageType'], 
        handler: (m: EitherFooOrBar['message']) => void
    ) {

    }
}

      



However, it will soon get pretty tedious to inject all these explicitly typed declarations - you will need to develop something that allows typescript to infer types for you, for example something like this question: Typescript inference / narrowing type invocation

+4


source







All Articles