Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EventTarget (and the Event type) are incompatible with typescript's CustomEvent type #47

Open
fardog opened this issue Nov 19, 2021 · 1 comment

Comments

@fardog
Copy link

fardog commented Nov 19, 2021

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.

@mattrunyon
Copy link

mattrunyon commented Dec 22, 2021

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>> { }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants