首页 文章

如何使用typescript创建EventHandler类?

提问于
浏览
1

我正在尝试将我的项目从javascript迁移到打字稿,并且在迁移类以处理事件时遇到问题 .

为避免双重描述添加/删除事件侦听器的选项,我们使用这样的包装器:

constructor() {
  this.windowResizeHandler = new MyEventHandler(
    target: window,
    event: 'resize',
    handler: e => this.handleResize_(e),
    options: {passive: true, capturing: true},
  );
} 

connectedCallback() {
  this.windowResizeHandler.add();
}

disconnectedCallback() {
  this.windowResizeHandler.remove();
}

现在我不知道如何在打字稿中写这个,而不会丢失有关事件输入的信息 . 例如:

document.createElement('button').addEventListener('click', e => {
  // Here e is MouseEvent.
});

但是,如果我写我的包装像:

interface EventHandlerParams {
  readonly target: EventTarget;
  readonly event: Event;
  readonly listener: (e: Event) => void;
  readonly params: AddEventListenerOptions;
}

export class EventHandler {
  public constructor(params: EventHandlerParams) {}
}

然后我放松了打字:

new MyEventHandler(
  target: document.createElement('button'),
  event: 'click',
  handler: e => { /* Here e is just Event not MouseEvent */ },
  options: {passive: true, capturing: true},
);

我有没有选择使用 lib.dom.d.ts 中的事件类型?

2 回答

  • 0

    @ titian-cernicova-dragomir我是这样的(不工作):

    interface Mapping {
      [Window]: WindowEventMap;
      [HTMLElement]: HTMLElementEventMap;
    }
    
    interface EventHandlerParams<TTarget extends keyof Mapping,
                                 TEventName extends keyof Mapping[TTarget],
                                 TEvent extends Mapping[TTarget][TEventName]> {
      readonly event: TEventName;
      readonly listener: (event: TEvent) => void;
      readonly params?: AddEventListenerOptions;
      readonly target: TTarget;
    }
    
    
    export class EventHandler<TTarget extends keyof Mapping,
                              TEventName extends keyof Mapping[TTarget],
                              TEvent extends Mapping[TTarget][TEventName]> {
      public constructor(params: EventHandlerParams<TTarget, TEventName, TEvent>) {}
    }
    

    但是不能使用它,因为类型不能是接口属性,并且没有任何其他选项可以为 TTarget 提供约束 .

  • 1

    lib.dom.ts 中有一个类型,它包含所有事件名称和事件参数类型之间的映射 . 它被称为 WindowEventMap .

    所以我们可以写例如下:

    interface EventHandlerParams<T extends keyof WindowEventMap> {
        readonly target: EventTarget;
        readonly event: T;
        readonly options: AddEventListenerOptions;
        readonly listener: (e: WindowEventMap[T]) => void
    }
    
    export class EventHandler<T extends keyof WindowEventMap> {
        public constructor(params: EventHandlerParams<T>) { }
    }
    
    
    new EventHandler({
        target: document.createElement('button'),
        event: 'click',
        options: { passive: true },
        listener: e => { e.x /* e is MouseEvent */ }
    });
    

    EventHandlerParams 现在是通用的,将捕获事件名称作为类型参数 T . 我们也做了 EventHandler 泛型,它的 T 将由传递给它的婴儿车决定 . 使用 T (将包含事件的字符串文字类型),我们可以从 WindowEventMap 访问事件的实际参数类型,并在我们的侦听器签名中使用它 .

    Note 我认为在3.0之前,侦听器的参数可能不会被推断为正确的类型(它们可能被推断为 any ) . 如果您遇到此问题,请告诉我,我可以提供3.0之前的版本 .

相关问题