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) {...}
}
source to share
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
source to share