Item 69: Provide a Type for this in Callbacks if It's Part of Their API
要点
- Understand how
this
binding works. - Provide a type for
this
in callbacks if it's part of your API. - Avoid dynamic
this
binding in new APIs. - 理解
this
绑定是如何工作的。 - 如果
this
是你 API 的一部分,在回调中提供this
的类型。 - 避免在新 API 中使用动态
this
绑定。
正文
ts
class C {
vals = [1, 2, 3]
logSquares() {
for (const val of this.vals) {
console.log(val ** 2)
}
}
}
const c = new C()
c.logSquares()
ts
const c = new C()
const method = c.logSquares
method()
ts
const c = new C()
const method = c.logSquares
method.call(c) // Logs the squares again
ts
document.querySelector('input')?.addEventListener('change', function (e) {
console.log(this) // Logs the input element on which the event fired.
})
ts
class ResetButton {
render() {
return makeButton({ text: 'Reset', onClick: this.onClick })
}
onClick() {
alert(`Reset ${this}`)
}
}
ts
class ResetButton {
constructor() {
this.onClick = this.onClick.bind(this)
}
render() {
return makeButton({ text: 'Reset', onClick: this.onClick })
}
onClick() {
alert(`Reset ${this}`)
}
}
ts
class ResetButton {
render() {
return makeButton({ text: 'Reset', onClick: this.onClick })
}
onClick = () => {
alert(`Reset ${this}`) // "this" refers to the ResetButton instance.
}
}
js
class ResetButton {
constructor() {
this.onClick = () => {
alert(`Reset ${this}`) // "this" refers to the ResetButton instance.
}
}
render() {
return makeButton({ text: 'Reset', onClick: this.onClick })
}
}
ts
function addKeyListener(
el: HTMLElement,
listener: (this: HTMLElement, e: KeyboardEvent) => void
) {
el.addEventListener('keydown', (e) => listener.call(el, e))
}
ts
function addKeyListener(
el: HTMLElement,
listener: (this: HTMLElement, e: KeyboardEvent) => void
) {
el.addEventListener('keydown', (e) => {
listener(el, e)
// ~ Expected 1 arguments, but got 2
})
}
ts
function addKeyListener(
el: HTMLElement,
listener: (this: HTMLElement, e: KeyboardEvent) => void
) {
el.addEventListener('keydown', (e) => {
listener(e)
// ~~~~~~~~ The 'this' context of type 'void' is not assignable
// to method's 'this' of type 'HTMLElement'
})
}
ts
declare let el: HTMLElement
addKeyListener(el, function (e) {
console.log(this.innerHTML)
// ^? this: HTMLElement
})
ts
class Foo {
registerHandler(el: HTMLElement) {
addKeyListener(el, (e) => {
console.log(this.innerHTML)
// ~~~~~~~~~ Property 'innerHTML' does not exist on 'Foo'
})
}
}