如何为 TouchEvent 处理程序定义 JSDoc
How to define JSDoc for TouchEvent handler
我正在使用适当的 JSDoc 更新我的 shorter-js
代码库以生成 TypeScript 定义,但我无法缩小这个范围。
我有使用原生 Element.addEventListener
的 on()
代码段,到目前为止还不错,
问题是当使用 TouchEvent
作为实际处理程序的参数时,TypeScript 会抛出 4 行错误,请参见下面的代码片段。
/**
* @param {HTMLElement | Element | Document} element event.target
* @param {string} eventName event.type
* @param {EventListener} handler callback
* @param {EventListenerOptions | boolean | undefined} options other event options
*/
function on(element, eventName, handler, options) {
const ops = options || false;
element.addEventListener(eventName, handler, ops);
}
/**
* test handler
* @type {EventListener}
* @param {TouchEvent} e
*/
function touchdownHandler(e){
console.log(e.touches)
}
// test invocation
on(document.body, 'touchdown', touchdownHandler);
body {height: 100%}
on(document.body, 'touchdown', touchdownHandler)
调用抛出这 4 行错误:
Argument of type '(e: TouchEvent) => void' is not assignable to parameter of type 'EventListener'.
Type '(e: TouchEvent) => void' is not assignable to type 'EventListener'.
Types of parameters 'e' and 'evt' are incompatible.
Type 'Event' is missing the following properties from type 'TouchEvent': altKey, changedTouches, ctrlKey, metaKey, and 7 more.
事实上,我在使用 document.body.addEventListener(...)
调用时得到了完全相同的结果。所以我在我的 index.d.ts
中尝试了 various definitions,但没有解决这个问题。
据我所知,我认为我需要在我的 index.d.ts
中定义一些东西,然后在 touchdownHandler
.
的 JSDoc 中使用它
有什么建议吗?
这里的问题是您需要提供 addEventListener
事件的实际类型,因此它会映射处理程序以接受这种特定类型的事件。 dom.d.ts
声明(DOM 库)包含此特定用途的事件映射。您的目标是确保 eventName
映射到处理程序的事件类型。
虽然在 TS 中我们可以使用参数类型,所以它可以在没有泛型的情况下完成,但你不能用 JSDoc 做同样的事情,所以我们必须为事件类型引入模板变量:
/**
* @template {keyof HTMLElementEventMap} T
* @param {HTMLElement} element
* @param {T} eventName
*/
还有其他事件地图,但在大多数情况下这就足够了。如果不是 - 检查 dom.d.ts
源代码。
接下来我们需要输入处理程序:
/**
* @template {keyof HTMLElementEventMap} T
* @param {HTMLElement} element
* @param {T} eventName
* @param {(event: HTMLElementEventMap[T]) => void} handler
*/
在这种情况下,如果 T
将是 'click'
,我们将在处理程序中得到 event
作为 HTMLElementEventMap['click']
,即 MouseEvent
。
最后 - options
。在 JSDoc 中,您可以将参数标记为可选,而不是指定 undefined
:
/**
* @template {keyof HTMLElementEventMap} T
* @param {HTMLElement} element
* @param {T} eventName
* @param {(event: HTMLElementEventMap[T]) => void} handler
* @param {EventListenerOptions | boolean} [options]
*/
这将如您所愿。
完整代码:
/**
* @template {keyof HTMLElementEventMap} T
* @param {HTMLElement} element
* @param {T} eventName
* @param {(event: HTMLElementEventMap[T]) => void} handler
* @param {EventListenerOptions | boolean} [options]
*/
function on(element, eventName, handler, options) {
const ops = options || false;
element.addEventListener(eventName, handler, ops);
}
/**
* test handler
* @param {TouchEvent} e
*/
function touchdownHandler(e) {
console.log(e.touches)
}
// test invocation
on(document.body, 'touchend', touchdownHandler);
要在其中声明,您必须使用 Generics:
declare function on<T extends keyof HTMLElementEventMap>(element: HTMLElement, eventName: T, handler: (event: HTMLElementEventMap[T]) => void, options?: EventListenerOptions | boolean): void;
因为我已经标记了一个答案,所以我也将提供我的解决方案,这比我想象的要简单得多:利用 EventListenerObject
及其 handleEvent
方法:
/**
* Add eventListener to an `Element` | `HTMLElement` | `Document` | `Window` target.
*
* @param {HTMLElement | Element | Document | Window} element event.target
* @param {string} eventName event.type
* @param {EventListenerObject['handleEvent']} handler callback
* @param {(EventListenerOptions | boolean)=} options other event options
*/
function on(element, eventName, handler, options) {
const ops = options || false;
element.addEventListener(eventName, handler, ops);
}
现在一切正常。
on(document, 'load', (e) => console.log(e), false)
on(window, 'resize', (e) => console.log(e.type), false)
/**
* test handler
* @type {(event: Event) => void}
* @param {TouchEvent} e
*/
function touchdownHandler(e) {
console.log(e.touches)
}
const div = document.createElement('div')
on(div, 'touchstart', touchdownHandler, false)
const main = document.createElement('main')
on(main, 'touchstart', touchdownHandler, false)
我正在使用适当的 JSDoc 更新我的 shorter-js
代码库以生成 TypeScript 定义,但我无法缩小这个范围。
我有使用原生 Element.addEventListener
的 on()
代码段,到目前为止还不错,
问题是当使用 TouchEvent
作为实际处理程序的参数时,TypeScript 会抛出 4 行错误,请参见下面的代码片段。
/**
* @param {HTMLElement | Element | Document} element event.target
* @param {string} eventName event.type
* @param {EventListener} handler callback
* @param {EventListenerOptions | boolean | undefined} options other event options
*/
function on(element, eventName, handler, options) {
const ops = options || false;
element.addEventListener(eventName, handler, ops);
}
/**
* test handler
* @type {EventListener}
* @param {TouchEvent} e
*/
function touchdownHandler(e){
console.log(e.touches)
}
// test invocation
on(document.body, 'touchdown', touchdownHandler);
body {height: 100%}
on(document.body, 'touchdown', touchdownHandler)
调用抛出这 4 行错误:
Argument of type '(e: TouchEvent) => void' is not assignable to parameter of type 'EventListener'.
Type '(e: TouchEvent) => void' is not assignable to type 'EventListener'.
Types of parameters 'e' and 'evt' are incompatible.
Type 'Event' is missing the following properties from type 'TouchEvent': altKey, changedTouches, ctrlKey, metaKey, and 7 more.
事实上,我在使用 document.body.addEventListener(...)
调用时得到了完全相同的结果。所以我在我的 index.d.ts
中尝试了 various definitions,但没有解决这个问题。
据我所知,我认为我需要在我的 index.d.ts
中定义一些东西,然后在 touchdownHandler
.
有什么建议吗?
这里的问题是您需要提供 addEventListener
事件的实际类型,因此它会映射处理程序以接受这种特定类型的事件。 dom.d.ts
声明(DOM 库)包含此特定用途的事件映射。您的目标是确保 eventName
映射到处理程序的事件类型。
虽然在 TS 中我们可以使用参数类型,所以它可以在没有泛型的情况下完成,但你不能用 JSDoc 做同样的事情,所以我们必须为事件类型引入模板变量:
/**
* @template {keyof HTMLElementEventMap} T
* @param {HTMLElement} element
* @param {T} eventName
*/
还有其他事件地图,但在大多数情况下这就足够了。如果不是 - 检查 dom.d.ts
源代码。
接下来我们需要输入处理程序:
/**
* @template {keyof HTMLElementEventMap} T
* @param {HTMLElement} element
* @param {T} eventName
* @param {(event: HTMLElementEventMap[T]) => void} handler
*/
在这种情况下,如果 T
将是 'click'
,我们将在处理程序中得到 event
作为 HTMLElementEventMap['click']
,即 MouseEvent
。
最后 - options
。在 JSDoc 中,您可以将参数标记为可选,而不是指定 undefined
:
/**
* @template {keyof HTMLElementEventMap} T
* @param {HTMLElement} element
* @param {T} eventName
* @param {(event: HTMLElementEventMap[T]) => void} handler
* @param {EventListenerOptions | boolean} [options]
*/
这将如您所愿。
完整代码:
/**
* @template {keyof HTMLElementEventMap} T
* @param {HTMLElement} element
* @param {T} eventName
* @param {(event: HTMLElementEventMap[T]) => void} handler
* @param {EventListenerOptions | boolean} [options]
*/
function on(element, eventName, handler, options) {
const ops = options || false;
element.addEventListener(eventName, handler, ops);
}
/**
* test handler
* @param {TouchEvent} e
*/
function touchdownHandler(e) {
console.log(e.touches)
}
// test invocation
on(document.body, 'touchend', touchdownHandler);
要在其中声明,您必须使用 Generics:
declare function on<T extends keyof HTMLElementEventMap>(element: HTMLElement, eventName: T, handler: (event: HTMLElementEventMap[T]) => void, options?: EventListenerOptions | boolean): void;
因为我已经标记了一个答案,所以我也将提供我的解决方案,这比我想象的要简单得多:利用 EventListenerObject
及其 handleEvent
方法:
/**
* Add eventListener to an `Element` | `HTMLElement` | `Document` | `Window` target.
*
* @param {HTMLElement | Element | Document | Window} element event.target
* @param {string} eventName event.type
* @param {EventListenerObject['handleEvent']} handler callback
* @param {(EventListenerOptions | boolean)=} options other event options
*/
function on(element, eventName, handler, options) {
const ops = options || false;
element.addEventListener(eventName, handler, ops);
}
现在一切正常。
on(document, 'load', (e) => console.log(e), false)
on(window, 'resize', (e) => console.log(e.type), false)
/**
* test handler
* @type {(event: Event) => void}
* @param {TouchEvent} e
*/
function touchdownHandler(e) {
console.log(e.touches)
}
const div = document.createElement('div')
on(div, 'touchstart', touchdownHandler, false)
const main = document.createElement('main')
on(main, 'touchstart', touchdownHandler, false)