event-target-shim
event-target-shim copied to clipboard
`EventTarget` (and the `Event` type) are incompatible with typescript's `CustomEvent` type
The CustomEvent
type, which inherits the Event
interface, are both present in the typescript standard library definitions. However they appear to be incompatible with the types this library exports; meaning if you define:
type ArbitraryDetail = {
cool: boolean
}
type ArbitraryEvent = CustomEvent<ArbitraryDetail>
class MyClass extends EventTarget<{arbitrary: ArbitraryEvent}> {
// …
this will not compile, as the CustomEvent
class is not seen as fulfilling Event
as provided by event-target-shim
. Before version 6 of this library, this worked as (although the generic wasn't really being enforced while emitting events):
class MyClass extends EventTarget<{arbitrary: ArbitraryEvent}, {}> {
// …
In looking through the library, I didn't see anywhere that seemed to support this "events plus arbitrary data" pattern that CustomEvent
allows. I can replicate it by creating an actual event definition, something like:
class ArbitraryEvent extends Event<'arbitrary'> {
constructor(public readonly detail: ArbitraryDetail) {
super('arbitrary')
}
}
…and that's not half bad, but I was wondering if there were any plans to provide interoperability with the types the stdlib already provides, or if there was methods already and I had missed them, or misunderstood some usage.
I am using this which seems to play nice w/ both types. I use this constructor instead of CustomEvent
when emitting events. If I use strict mode, I also get errors if I try to pass an event with the wrong detail or no detail when one is specified.
It seems the problem is the browser's CustomEvent
does not template the type field, so it is always just string
.
export class EventShimCustomEvent<
T extends string,
D = unknown
> extends CustomEvent<D> {
type!: T;
constructor(typeArg: T, eventInitDict?: CustomEventInit<D>) {
super(typeArg, eventInitDict);
}
}
Also, I am using this so I don't have to duplicate the event type twice in the event map
import type { Event } from 'event-target-shim';
type EventMap = {
onUpdate: Event;
onEdit: CustomEvent<SomeDetailType>;
};
export type CustomEventMap<M extends Record<string, Event>> = {
[T in keyof M]: T extends string
? M[T] extends CustomEvent<infer D>
? EventShimCustomEvent<T, D>
: M[T] extends Event
? Event<T>
: never
: never;
};
class MyEventTarget extends EventTarget<CustomEventMap<EventMap>> { }