interface IntermediateEventTarget<EventMap> extends EventTarget {
  addEventListener<K extends keyof EventMap>(
    type: K,
    listener: (event: EventMap[K]) => unknown,
    options?: boolean | AddEventListenerOptions
  ): void

  addEventListener(
    type: string,
    callback: EventListenerOrEventListenerObject | null,
    options?: EventListenerOptions | boolean
  ): void
}

/**
 * Allows to extend a class by the `EventTarget` and declare events dispatched by the class.
 *
 * These events will be type checked by consumers! That is, when using `addEventListener()`
 *
 * **Example**
 *
 * ```typescript
 * interface ActivityEventMap {
 *   "activity:start": CustomEvent<null>
 * }
 *
 * export class MyClass extends (EventTarget as TypedEventTarget<ActivityEventMap>) {
 * }
 * ```
 */
export type TypedEventTarget<EventMap extends object> = new () => IntermediateEventTarget<EventMap>

export interface TypedEvents<EventMap> {
  addEventListener<K extends keyof EventMap>(
    type: K,
    listener: (event: EventMap[K]) => void,
    options?: boolean | AddEventListenerOptions
  ): void

  addEventListener(
    type: string,
    callback: EventListenerOrEventListenerObject | null,
    options?: EventListenerOptions | boolean
  ): void
}
