如何在TypeScript中将类方法作为jQuery事件处理程序附加

5

我正在将一些JavaScript代码转换为TypeScript,但我不能弄清楚jQuery EventHandler的签名应该是什么样子。

这就是我在JavaScript中拥有的东西,但简化为更通用的术语(我使用自定义事件通过元素分布某种发布-订阅或可观察模式):

Observer.prototype._subscribe = function() {
  this._row.bind('onItemChanged', this, this._onChangedHandler);
};
Observer.prototype._onChangedHandler= function(event, someString, someObject) {
  var that = event.data;
  if (someString === '42') {
    that.coolMethod(someObject);
  } else if (someString === '69') {
    that.otherCoolMethod(someObject);
  }
};

在另一个原型中,我会调用触发器来使用事件通知观察者,并且至少包含数据的两个参数(someString 和 someObject):

Subject.prototype.foo = function() {
  // Trigger the event so Observer will be notified and pass in the string and the object (or any data whatsoever)
  this._element.trigger("onItemChanged", ["42", this._data]);
};

现在我在尝试用 TypeScript 编写这段代码,但我认为它应该是这个样子:

export class Observer {
  private _subscribe (): void {
        this._element.bind('onItemChanged', this, this._onChangedHandler);
  }
  private _onChangedHandler(event: JQueryEventObject, someString: string, someObject: FooBarClass) {
    let that = event.data as Observer;
    if (someString === '42') {
      that.coolMethod(someObject);
    } else if (someString === '69') {
      that.otherCoolMethod(someObject);
    }
  }
}

这个 TypeScript 无法编译,但是给出了以下错误信息:
参数类型 '(event: JQueryEventObject, someString: string, someObject: FooBarClass) => void' 不能赋值给类型 'EventHandler | EventHandlerBase>' 的参数。 类型 '(event: JQueryEventObject, someString: string, someObject: FooBarClass) => void' 不能赋值给类型 'EventHandlerBase>'。 参数 'event' 和 't' 的类型不兼容。 类型 'Event' 不能赋值给类型 'JQueryEventObject'。
那么事件处理程序的签名(参数类型)应该是什么样子的呢?
附注:如果你愿意,可以使用 jQuery::on() 代替 jQuery::bind() 进行重写。
此外,我并不关心获得正确的“this”的各种方式,除非我真的走错了路。编辑后(第一次回复后):
正如建议的那样,我重写了我的 TypeScript 以使我的问题更加清晰。我知道可以使用“fat arrow notation”来获得正确的“this”,但是我之前已经说过,我对此不感兴趣。我想让我的方法类型安全,那么我的处理程序方法的签名应该是什么样子的呢? 这确实有效。
private _subscribe (): void {
  this._element.on('onItemChanged', () => this._onChangedHandler);
}
private _onChangedHandler(event: JQueryEventObject, someString: string, someObject: FooBarClass) {
}

但是我本以为这个也应该会起作用:
private _subscribe(): void {
  this._element.on('onItemChanged', (event: JQueryEventObject, someString: string, someObject: FooBarClass) => { this._onChangedHandler(event, someString, someObject); });
}

但我仍然无法获得正确的事件类型以获得类型安全。使用“任何”类型,它确实可以编译:

private _subscribe(): void {
  this._element.on('onItemChanged', (event: any, someString: string, someObject: FooBarClass) => { this._onChangedHandler(event, someString, someObject); });
}
2个回答

2

通过将类型设置为“any”并在调试器中运行,我最终在运行时发现第一个参数的类型是“JQuery.Event”,当使用jQuery的类型定义时,TypeScript也可以正确编译。很遗憾tsc不能在编译时更早地告诉我这一点(或者我误解了问题中显示的错误)。 因此,无论是使用bind、fat arrow还是您自己保留正确上下文/this的方式,它应该看起来像这样:

export class Observer {
  private _element: JQuery;

  private _subscribe(): void {
    this._element.on('onItemChanged', (event: JQuery.Event, someString: string, someObject: FooBarClass) => { this._onChangedHandler(event, someString, someObject); });
  }

  private _onChangedHandler(event: JQuery.Event, someString: string, someObject: FooBarClass): void {
  }
}

虽然这样编译可以提供一定的类型安全,但我有点失望,因为我可以使用错误的签名附加处理程序,但它仍然可以编译。我猜这就是如何附加事件处理程序的方式。至少你可以直接调用具有类型安全性的方法并将其用作处理程序。

所以对于其他遇到此问题的人,签名应该像这样:

export class Observer {
  private _element: JQuery;

  private _subscribe(): void {
    this._element.on('anyevent', () => this._yourOwnHandler);
  }

  private _yourOwnHandler(event: JQuery.Event, ...args: any[]): void {
  }
}

“...args”可以是任何你想要的东西,它将为你提供所需的参数数量和类型。


1

P.P.S. 我并不关心如何获得正确的“this”(除非我真的走错了路)。

我知道你不想听这个,但是当你处理事件时,确实需要注意你的作用域。

this._element.bind('onItemChanged', this, () => {
    this._onChangedHandler();
});

我也建议您将 bind 替换为 on,因为 bind 已被弃用。

这个回答感觉有些奇怪,因为我认为您已经怀疑这两个方法了?


2
两种都是有效的评论,我需要解决它们,但这与我的问题无关。我想知道如何定义处理程序函数的参数类型。如果有必要,我可以使用两个建议重写问题,但是由于您不会向处理程序传递任何数据或参数,因此这并没有帮助。 - Huupke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接