microsoft / microsoft/TypeScript
Add a generic parameter to EventTarget for mapping events
Nessuno ha ancora preso questa issue.
- Lingua principale
- Go
- Stelle
- 111k
- Fork
- 14.4k
- Merge medio
- 1g 19h
- PR unite (30g)
- 117
Descrizione
Suggestion
🔍 Search Terms
EventTarget, addEventListener, removeEventListener
✅ Viability Checklist
- This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- This feature would agree with the rest of TypeScript's Design Goals.
⭐ Suggestion
Currently we can extend EventTarget to hook any given class into the DOM events system:
class Foo extends EventTarget {}
const instance = new Foo();
instance.addEventListener('my-event', (ev) => { ... });
However, in the case of EventTarget, it has an addEventListener definition like so:
interface EventTarget {
addEventListener(
type: string,
listener: EventListenerOrEventListenerObject | null,
options?: boolean | AddEventListenerOptions
): void;
dispatchEvent(event: Event): boolean;
removeEventListener(
type: string,
callback: EventListenerOrEventListenerObject | null,
options?: EventListenerOptions | boolean
): void;
}
declare var EventTarget: {
prototype: EventTarget;
new(): EventTarget;
};
Due to this, it seems impossible to strongly type the events of our class.
Remember how things like window work:
addEventListener<K extends keyof WindowEventMap>(
type: K,
listener: (this: Window, ev: WindowEventMap[K]) => any,
options?: boolean | AddEventListenerOptions
): void;
This means we have strongly typed event names and types, giving us good intellisense when we do window.addEventListener.
So my suggestion is that we do similar for EventTarget:
interface EventTarget<EventMap> {
addEventListener<K extends keyof EventMap>(
type: K,
listener: (this: any, ev: EventMap[K]) => any, // `this` has to be `any` i suppose since we don't know what it is at this point
options?: boolean | AddEventListenerOptions
): void;
}
We'd still want an overload which consumes string but that would just fall back to Event.
Also, I'm unaware of any work around, so if there is already a known one, please do tell.
We also can't override this as a workaround, for example:
class Foo extends EventTarget {
addEventListener<K extends keyof FooMap>(
type: K,
listener: (ev: FooMap[K]) => void,
options?: boolean | AddEventListenerOptions
): void;
// ...[implementation and other overloads here]
}
as this would be like doing:
type Handler = (ev: Event) => void;
const myHandler: Handler = (ev: CustomEvent) => void; // error since it needs to handle ANY `Event`
You could possibly hack around it with interfaces:
interface FooEventTarget extends EventTarget {
addEventListener<K extends keyof FooMap>(
type: K,
listener: (ev: FooMap[K]) => void,
options?: boolean | AddEventListenerOptions
): void;
addEventListener(
type: string,
callback: EventListenerOrEventListenerObject | null,
options?: EventListenerOptions | boolean
): void;
}
const eventTarget = EventTarget as {new(): FooEventTarget; prototype: FooEventTarget};
class MyClass extends eventTarget {}
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Direzione di ricerca
Parti dalle dichiarazioni di EventTarget, addEventListener, removeEventListener e dispatchEvent mostrate nell’issue, quindi confrontale con l’overload WindowEventMap esistente. Definisci cosa devono preservare il supporto alle mappe di eventi generiche e il fallback da string a Event; il lavoro è completo quando i nomi e i payload degli eventi personalizzati sono fortemente tipizzati, senza modificare il comportamento di JavaScript a runtime né interrompere le chiamate esistenti.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- javascript, typescript
- Ambito
- frontend, web-dev
- Tipo di issue
- Funzionalità
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Stato di attività
- Ferma
- Chiarezza
- Abbastanza chiara
- Idoneità per principianti
- 35/100