Search code examples
javascripttypescriptvue.jsvue-directives

How can i add property to already declared function's parameter type inside imported interface? TS2322


I'm importing DirectiveOptions from vue types.

Which has few functions with DirectiveFunction type.

This DirectiveFunction first parameter is HTMLElement. But i do not import this function type, i need to extend or add property to this functions first parameter.

How do I add a property to this HTMLElement type?

Here is code sandbox where the error occurs

import { DirectiveOptions } from 'vue'

interface HTMLElement {
    doStuff: (event: any) => void
}

const directive: DirectiveOptions = {
    bind(elem: HTMLElement, bind, vn){
        elem.doStuff = (event)=> {
            console.log('doing stuff')
        }
        document.body.addEventListener('click', elem.doStuff )
    },
    unbind(elem){
        document.body.removeEventListener('click', elem.doStuff)
    }
}

Compiler says Property 'doStuff' is missing in type 'HTMLElement' but required in type 'HTMLElement' because HTMLElement was already declared inside DirectiveOptions function parameter.

Even if I follow answer and create new interface extending HTMLElement same error occurs.

interface HTMLElementWithDoStuff extends HTMLElement {
  doStuff: (event: any) => void;
}

const directive: DirectiveOptions = {
  bind(elem: HTMLElementWithDoStuff, bind, vn) {
    elem.doStuff = (event) => {
      console.log("doing stuff");
    };
    document.body.addEventListener("click", elem.doStuff);
  },
  unbind(elem: HTMLElementWithDoStuff) {
    document.body.removeEventListener("click", elem.doStuff);
  }
};

Property 'doStuff' is missing in type 'HTMLElement' but required in type 'HTMLElementWithDoStuff'


Solution

  • I found the solution, the trick is that you need to create a new variable as a new type and not assign it in params.

    interface HTMLElementWithDoStuff extends HTMLElement {
      doStuff: (event: any) => void;
    }
    
    const directive: DirectiveOptions = {
      bind(el, bind, vn) {
        const elem = el as ExtendedHTMLElement
        elem.doStuff = (event) => {
          console.log("doing stuff");
        };
        document.body.addEventListener("click", elem.doStuff);
      },
      unbind(el) {
        const elem = el as ExtendedHTMLElement
        document.body.removeEventListener("click", elem.doStuff);
      }
    };