如何在Typescript中创建自定义事件?

jw5wzhpr  于 2022-12-05  发布在  TypeScript
关注(0)|答案(6)|浏览(244)

如何创建一个自定义事件类型脚本并使用它?我在Mozilla网站(https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent)的javascript上找到了此链接
我只是在自定义事件上做一些测试,但Typescript将其视为错误。我计划做的是将一些额外数据添加到details属性中以供以后使用:这是我代码。

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);
eit6fx6z

eit6fx6z1#

属性名称为detail而不是details。正确的代码应为:

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);
a11xaf1n

a11xaf1n2#

在可接受的答案中描述的解决方案完成了工作,但代价是失去了类型安全。

如果您希望保持类型安全,我建议您采取以下措施:

使用以下代码在源代码的@types文件夹中创建dom.d.ts文件(或配置typeRoots以确保TS编译器将在那里查找):

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;
        dispatchEvent<K extends keyof CustomEventMap>(ev: CustomEventMap[K]): void;
    }
}
export { }; //keep that for TS compiler.

这将扩充documentaddEventListener函数的global definition,以接受您的合成事件及其类型化参数。
现在您可以执行以下操作:

function onCustomEvent(event: CustomEvent<CustomParams>){
  this.[...] // this is Document
  event.detail ... //is your CustomParams type.
}
document.addEventListener('anothercustomevent', onCustomEvent);

这样,您就可以输入所有内容并对其进行控制。

qqrboqgw

qqrboqgw3#

最简单的办法是这样:

window.addEventListener("beforeinstallprompt", ((event: CustomEvent) => {
   console.log("Whoop!");
}) as EventListener);
oknrviil

oknrviil4#

CustomEvent是一个泛型类型。您可以将detail属性的类型作为参数传递(默认为any)。下面是它在lib.dom.d.ts(位于npm typescript安装的lib目录中)中的定义:

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

在OP的例子中,detail的类型是number

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);

上面,我也使用了lib.dom.d.ts中的HTMLElement类型。作为一个TypeScript的新手,我发现扫描这个文件并搜索“明显”的类型是非常有用的。

fhity93d

fhity93d5#

最后我采用了一种不同的方法。相反,我创建了一个扩展EventTarget的 Package 类。

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);
  }
};

和用法如下:

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);
s3fp2yjn

s3fp2yjn6#

可能过于复杂但类型安全?

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);
});

相关问题