如何将 属性 添加到已在导入接口中声明的函数的参数类型? TS2322

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

我正在从 vue 类型导入 DirectiveOptions

DirectiveFunction 类型的功能很少。

这个DirectiveFunction第一个参数是HTMLElement。但是我不导入这个函数类型,我需要扩展或添加 属性 到这个函数的第一个参数。

如何向 HTMLElement 类型添加 属性?

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)
    }
}

编译器说 属性 'doStuff' 在类型 'HTMLElement' 中缺失,但在类型 'HTMLElement' 中是必需的,因为 HTMLElement 已经声明内部 DirectiveOptions 函数参数。

即使我按照答案创建新接口扩展 HTMLElement 也会发生同样的错误。

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

属性 'doStuff' 在类型 'HTMLElement' 中缺失,但在类型 'HTMLElementWithDoStuff'

中是必需的

更改现有类型通常不是一个好主意,尤其是来自您应用外部的类型。

您应该创建自己的 extends HTMLElement 类型,将 属性 添加到其中,然后使用该新类型。

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

现在打字稿将强制任何传入的 HTMLElement 也将有一个 doStuff 方法。

Updated Sandbox

我找到了解决办法,诀窍是你需要创建一个新变量作为新类型,而不是在参数中分配它。

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