title: Infer callback argument from type parameter
body: <p>I wrote a React hook that adds an event listener to an event target with automatic cleanup. The implementation is fairly simple, but I’m having issues with the type definitions.</p>
  <p>I created the following working implementation.</p>
  <pre class="lang-js prettyprint-override"><code>type Listener&lt;E extends Event = Event&gt; = (event: E) =&gt; void;
  type Options = boolean | AddEventListenerOptions;
  
  function useEventListener&lt;K extends keyof DocumentEventMap&gt;(
    target: Document,
    type: K,
    listener: Listener&lt;DocumentEventMap[K]&gt;,
    options?: Options,
  ): void;
  function useEventListener&lt;T extends HTMLElement, K extends keyof HTMLElementEventMap&gt;(
    target: T,
    type: K,
    listener: Listener&lt;HTMLElementEventMap[K]&gt;,
    options?: Options,
  ): void;
  function useEventListener(
    target: EventTarget,
    type: string,
    listener: Listener,
    options?: Options,
  ): void;
  function useEventListener(
    target: EventTarget,
    type: string,
    listener: Listener,
    options?: Options,
  ): void {
    useEffect(() =&gt; {
      target.addEventListener(type, listener, options);
  
      return () =&gt; target.removeEventListener(type, listener, options);
    }, [listener, options, target, type]);
  }
  
  function onClick(event: MouseEvent) {}
  
  useEventListener(document, 'click', onClick);
  </code></pre>
  <p>However, this means all acceptable event targets need to be added explicitly. It would be much nicer if this could be deferred automatically. I tried the following:</p>
  <pre class="lang-js prettyprint-override"><code>function useEventListener&lt;T extends EventTarget&gt;(
    target: T,
    type: Parameters&lt;EventTarget['addEventListener']&gt;[0],
    listener: Parameters&lt;EventTarget['addEventListener']&gt;[1],
    options?: Parameters&lt;EventTarget['addEventListener']&gt;[2]
  ): void {}
  
  function onClick(event: MouseEvent) {}
  
  useEventListener(document, 'click', onClick);
  </code></pre>
  <p>… but this throws an error.</p>
  <p>Can I defer the event listener type from the event target passed in for <strong>any</strong> type of event target?</p>
  <p><a href="https://www.typescriptlang.org/play/?ssl=1&amp;ssc=1&amp;pln=44&amp;pc=1#code/C4TwDgpgBAMglgZ2BAdhATgHgKJQgD2RQBMEpsA3VYKAXnKpWAD46oAKCR4ALnIEo6rCgHs4xANwAoUJCgB5MMDgiUZegCMRIgDYQAhiigAfKAEFixStXhJUGRctUJpUgGYBXFAGMnRjwgQ1ky2RBiYANJ4hKikUADWECAiblAAIiLeHgC21MHAALL6YMzsUlBQwProAOYQvOmZOdQANOWV4BB8EW0VOohh6Hyh9lgZWblM+UVgANoRALrMvVAiSipqAPx8jhsIbfx8ouLSnj5+UAFB3CNoWAAq0URxABL3BTDYepPALVBRBGeZESyVSbw+XwgP2mxVK7SqtXqfHuK1kXX+K36djuwwGo0w4M+3zy3Bm8yWKzWfgQ2wU62cByOYkk7i8vg2l0C+VuGDKFQRdQa+Xu1UFqM6fCQ6DgKBqmLxONgCowlPpWx2av2UkOUGOLLO7NUnOuNmV6D5lVFSIY1BFiN+8IlUClMrl7Sxg1x2JV7Spe1puwZ2qZ4igAG8AL5SVnnDmqADC-W88U43D4BREV3ygjDUCjUizNzN7GITR+fwA5N4k-EK38EzX+K4Y4b-Fyi970AAmTCPQGxMjCq0sC0C60ox2QPgABWq+lyyHQCBw3DtgtmFf0lm5ZorS1mAAYFvLOzO5wuMMuh-aN1urB3BnvmLMAIzH32a2mz9Dz+qXle2sOt7bg+oxPrMXYLMGurMuG+bRoWpqdl2JZlq0UBVjWdarCgiZwMmTZSEAA" rel="nofollow noreferrer">Playground</a></p>