'How do you create custom Event in Typescript?
How do i create a customEvent Typescript and use it? I found this link on javascript on Mozilla site (https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent)
I am just doing some testing on custom Event but Typescript see it as an error. what i am planning on doing is add some extra data into the details property to use later: here is my code.
let div:any=document.getElementById("my_div");
let c_event = new CustomEvent("build",{'details':3 });
div.addEventListener("build",function(e:Event){
console.log(e.details);
}.bind(this));
div.dispatchEvent(c_event);
Solution 1:[1]
The property name is detail and not details. The correct code needs to be:
let div: any = document.getElementById("my_div");
let c_event = new CustomEvent("build",{detail: 3});
div.addEventListener("build", function(e: CustomEvent) { // change here Event to CustomEvent
console.log(e.detail);
}.bind(this));
div.dispatchEvent(c_event);
Solution 2:[2]
Simplest way is like so:
window.addEventListener("beforeinstallprompt", ((event: CustomEvent) => {
console.log("Whoop!");
}) as EventListener);
Solution 3:[3]
CustomEvent is a generic type. You can pass the type of the detail property as a parameter (it defaults to any). Here is how it is defined in lib.dom.d.ts (which is in the lib directory of your npm typescript installation):
interface CustomEvent<T = any> extends Event {
/**
* Returns any custom data event was created with. Typically used for synthetic events.
*/
readonly detail: T;
initCustomEvent(typeArg: string, canBubbleArg: boolean, cancelableArg: boolean, detailArg: T): void;
}
In the OP's example, the type of detail is number. So, building on the answer from @Diullei:
let div: HTMLElement | null = document.getElementById("my_div");
let c_event = new CustomEvent<number>("build", {detail: 3});
div.addEventListener("build", function(e: CustomEvent<number>) { // change here Event to CustomEvent
console.log(e.detail);
}.bind(this));
div.dispatchEvent(c_event);
Above, I've also used the HTMLElement type from lib.dom.d.ts.
As a newcomer to TypeScript, I found it very useful to scan this file, and search it for 'obvious' types.
Solution 4:[4]
The solution described in the accepted answer gets the job done but for the cost of losing type safety.
If you want to keep the type-safety going I would suggest the following:
Create dom.d.ts file in @types folder in your sources (or configure typeRoots to make sure that TS compiler will look there) with the following:
interface CustomEventMap {
"customnumberevent": CustomEvent<number>;
"anothercustomevent": CustomEvent<CustomParams>;
}
declare global {
interface Document { //adds definition to Document, but you can do the same with HTMLElement
addEventListener<K extends keyof CustomEventMap>(type: K,
listener: (this: Document, ev: CustomEventMap[K]) => void): void;
}
}
export { }; //keep that to TS compliler.
This will augment global definition of document's addEventListener function to accept your synthetic event and its typed params.
now you can do:
function onCustomEvent(event: CustomEvent<CustomParams>){
this.[...] // this is Document
event.detail ... //is your CustomParams type.
}
document.addEventListener('anothercustomevent', onCustomEvent);
This way you will have everything typed and under control.
Solution 5:[5]
I ended up taking a different approach. Instead, I made a wrapper class that extended EventTarget.
type AudioEvent = {bytes: Uint8Array};
interface IAudioEventTarget {
addListener(callback: (evt: CustomEvent<AudioEvent>) => void): void
dispatch(event: AudioEvent): boolean;
removeListener(callback: (evt: CustomEvent<AudioEvent>) => void): void
}
class AudioEventTarget extends EventTarget implements IAudioEventTarget {
private readonly targetType = 'audio-event';
addListener(callback: (evt: CustomEvent<AudioEvent>) => void): void {
return this.addEventListener(this.targetType, callback as (evt: Event) => void);
}
dispatch(event: AudioEvent): boolean {
return this.dispatchEvent(new CustomEvent(this.targetType, { detail: event }));
}
removeListener(callback: (evt: CustomEvent<AudioEvent>) => void): void {
return this.removeEventListener(this.targetType, callback as (evt: Event) => void);
}
};
And usage is as follows:
const audioEventTarget = new AudioEventTarget();
const listener = (audioEvent: CustomEvent<AudioEvent>) => {
console.log(`Received ${audioEvent.detail.bytes.length} bytes`);
}
audioEventTarget.addListener(listener);
audioEventTarget.dispatch({bytes: new Uint8Array(10)});
audioEventTarget.removeListener(listener);
Solution 6:[6]
maybe overly complicated but typesafe?
interface FizzInfo {
amount: string;
}
interface BuzzInfo {
level: number;
}
interface FizzBuzzEventMap {
fizz: CustomEvent<FizzInfo>;
buzz: CustomEvent<BuzzInfo>;
}
interface FizzerBuzzer extends EventTarget {
addEventListener<K extends keyof FizzBuzzEventMap>(type: K, listener: (this: FizzerBuzzer, ev: FizzBuzzEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
removeEventListener<K extends keyof FizzBuzzEventMap>(type: K, listener: (this: FizzerBuzzer, ev: FizzBuzzEventMap[K]) => void, options?: boolean | EventListenerOptions): void;
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
}
class FizzerBuzzer extends EventTarget {
numFizz: number = 0;
numBuzz: number = 0;
start(): void {
setInterval(() => this.emitFizz(), 3000);
setInterval(() => this.emitBuzz(), 5000);
}
emitFizz(): void {
++this.numFizz;
this.dispatchEvent(new CustomEvent<FizzInfo>('fizz', {
detail: { amount: this.numFizz.toString() },
}));
}
emitBuzz(): void {
++this.numBuzz;
this.dispatchEvent(new CustomEvent<BuzzInfo>('buzz', {
detail: { level: this.numBuzz },
}));
}
}
const fb = new FizzerBuzzer();
fb.addEventListener('fizz', (ev) => {
console.assert(typeof ev.detail.amount === 'string', 'bad!');
console.log(ev.detail.amount);
});
fb.addEventListener('buzz', (ev) => {
console.assert(typeof ev.detail.level === 'number', 'bad');
console.log(ev.detail.level);
});
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Diullei |
| Solution 2 | sidonaldson |
| Solution 3 | Matt Wallis |
| Solution 4 | |
| Solution 5 | Bryan McGrane |
| Solution 6 | gman |
