Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

333
Visualizações
How to define JSDoc for TouchEvent handler

I'm updating my shorter-js codebase with proper JSDoc to generate TypeScript definitions but I'm unable to narrow down this one.

I have the on() snippet which makes use of native Element.addEventListener, so far so good, the problem is when using TouchEvent as a parameter for an actual handler, TypeScript throws a 4 line error, see below snippet.

/**
 * @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%}

The on(document.body, 'touchdown', touchdownHandler) invocation throws this 4 line error:

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.

In fact I get the exact same when using document.body.addEventListener(...) invocation. So I've tried various definitions within my index.d.ts, but nothing to resolve this.

To my knowledge I think I need to define something in my index.d.ts, then use it in the JSDoc for the touchdownHandler.

Any suggestions?

about 4 years ago · Juan Pablo Isaza
2 Respostas
Responde à pergunta

0

Problem here is that you need to provide addEventListener with actual type of event, so it would map handler to accept this particular kind of event. dom.d.ts declaration (DOM Library) contain event maps for this particular usage. Your goal is to ensure that eventName is mapped to event type of handler.

While in TS we can use param types so it can be done without generics, you can't do same with JSDoc, so we have to introduce template variable for Event Type:

/**
 * @template {keyof HTMLElementEventMap} T
 * @param {HTMLElement} element
 * @param {T} eventName
*/

There are other event maps, but in most cases this will be enough. If not - check dom.d.ts source code.

Next we need to type out handler:

/**
 * @template {keyof HTMLElementEventMap} T
 * @param {HTMLElement} element
 * @param {T} eventName
 * @param {(event: HTMLElementEventMap[T]) => void} handler
 */

In this case, if T will be 'click', we will get event in handler as HTMLElementEventMap['click'], which is MouseEvent.

And last - options. In JSDoc you can mark parameter as optional instead of specifying undefined:

/**
 * @template {keyof HTMLElementEventMap} T
 * @param {HTMLElement} element
 * @param {T} eventName
 * @param {(event: HTMLElementEventMap[T]) => void} handler
 * @param {EventListenerOptions | boolean} [options]
 */

This will work as you expect.

Full Code:

/**
 * @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);

Sandbox

To declare this in you have to use Generics:

declare function on<T extends keyof HTMLElementEventMap>(element: HTMLElement, eventName: T, handler: (event: HTMLElementEventMap[T]) => void, options?: EventListenerOptions | boolean): void;
about 4 years ago · Juan Pablo Isaza Relatório

0

Because I already marked an answer, I will provide my solution as well, which is much more simple than I thought: make use of the EventListenerObject with its handleEvent method:

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

Everything works as expected now.

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)
about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda