You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Sometimes we get some weird type error about the fact that we cannot specify a more specific event type in our event handlers because event target isn't typed and thus allows any event to be dispatched to any event name.
To get around this we can extend our Evented interface to actually be typesafe and to receive an optional EventMap that would allow downstream classes to specify a typed map of events that is being used.
This can be propagated to the js-async-init too, and it would be possible to do things like:
It would be a breaking change on the types, but we don't really use the StartReturn and StopReturn types much. And actually all the generic types would be optional here. The EventMap can be first since it is just likely to be used more.
Anyway this is what we would do to Evented to achieve this:
typeEventListenerOrEventListenerObject<TextendsEvent>=((evt: T)=>void)|{handleEvent(evt: T): void};classTypedEventTarget<EextendsRecord<string,Event>=Record<string,Event>>{privatetarget: EventTarget=newEventTarget();// General case: any string maps to an EventaddEventListener(type: string,listener: EventListenerOrEventListenerObject<Event>,options?: boolean|AddEventListenerOptions): void;// Specific case: string is a key in EaddEventListener<KextendskeyofE>(type: K,listener: EventListenerOrEventListenerObject<E[K]>,options?: boolean|AddEventListenerOptions): void;// Implementation for addEventListeneraddEventListener(type: string,listener: EventListenerOrEventListenerObject<Event>,options?: boolean|AddEventListenerOptions){this.target.addEventListener(type,listenerasEventListenerOrEventListenerObject<Event>,options);}// General case: any string maps to an EventremoveEventListener(type: string,listener: EventListenerOrEventListenerObject<Event>,options?: boolean|EventListenerOptions): void;// Specific case: string is a key in EremoveEventListener<KextendskeyofE>(type: K,listener: EventListenerOrEventListenerObject<E[K]>,options?: boolean|EventListenerOptions): void;// Implementation for removeEventListenerremoveEventListener(type: string,listener: EventListenerOrEventListenerObject<Event>,options?: boolean|EventListenerOptions){this.target.removeEventListener(type,listenerasEventListenerOrEventListenerObject<Event>,options);}dispatchEvent<KextendskeyofE>(type: K,event: E[K]){this.target.dispatchEvent(eventasEvent);}}
The above is pseudo code generated by chatgpt. What's cool is that it preserves the ability to not bother specifying specific types if you don't want to. You can still get the original behaviour of event map not caring about the type of the event. When you do care, you give it a much more specific type.
One might be careful that EventQUICConnectionStart.name is of type string and not the literal type of EventQUICConnectionStart.name. So I'm not sure how TS will end up inferring it or not. If not, then you have to do addEventListener<'EventQUICConnectionStart'>(...).
This is what it looks like when we have to add specific event types:
quicServer.addEventListener(
events.EventQUICServerConnection.name,
// @ts-ignore
(evt: events.EventQUICServerConnection) => {
const connection = evt.detail;
connection.addEventListener(
events.EventQUICConnectionStream.name,
// @ts-ignore
async (evt: events.EventQUICConnectionStream) => {
const stream = evt.detail;
// Graceful close of writable
process.stderr.write('>>>>>>>>> HANDLING THE QUIC SERVER STREAM\n');
await stream.writable.close();
// Consume until graceful close of readable
for await (const _ of stream.readable) {
// Do nothing, only consume
}
process.stderr.write('<<<<<<<< HANDLED THE QUIC SERVER STREAM\n');
}
);
}
);
It doesn't happen when those event handlers are defined elsewhere, but this can be annoying. If the Class.name could be made into literal types would be even easier to do...
Specification
Sometimes we get some weird type error about the fact that we cannot specify a more specific event type in our event handlers because event target isn't typed and thus allows any event to be dispatched to any event name.
To get around this we can extend our
Evented
interface to actually be typesafe and to receive an optionalEventMap
that would allow downstream classes to specify a typed map of events that is being used.This can be propagated to the
js-async-init
too, and it would be possible to do things like:It would be a breaking change on the types, but we don't really use the
StartReturn
andStopReturn
types much. And actually all the generic types would be optional here. TheEventMap
can be first since it is just likely to be used more.Anyway this is what we would do to
Evented
to achieve this:The above is pseudo code generated by chatgpt. What's cool is that it preserves the ability to not bother specifying specific types if you don't want to. You can still get the original behaviour of event map not caring about the type of the event. When you do care, you give it a much more specific type.
The relevant type map can then look like this:
One might be careful that
EventQUICConnectionStart.name
is of typestring
and not the literal type ofEventQUICConnectionStart.name
. So I'm not sure how TS will end up inferring it or not. If not, then you have to doaddEventListener<'EventQUICConnectionStart'>(...)
.A little more boilerplate.
Additional Context
Tasks
Evented
js-async-init
before enabling this feature@ts-ignore
.The text was updated successfully, but these errors were encountered: