在打字稿中,我如何使用声明的函数扩展全局接口

时间:2020-07-20 16:40:26

标签: typescript typescript-typings

我正在研究一个旧式javascript项目,目前正在为一些较流行的功能添加打字稿声明 .d.ts 文件,以更好地进行vscode类型定义。

当前设置在该函数中包含多个重载,并根据这些重载选项返回一个设置值。

declare function createChild(type: "div", options?: CreateChild_Options, node?: HTMLElement): HTMLDivElement;
declare function createChild(type: "span", options?: CreateChild_Options, node?: HTMLElement): HTMLSpanElement;
declare function createChild(type: "input", options?: CreateChild_Options, node?: HTMLElement): HTMLInputElement;

我还想将.createChild函数添加到要返回的HTMLElements中。

可能它可以写为

interface CreateChild_DivElement extends HTMLDivElement {
    createChild: createChild
}

,而我将HTMLDivElement替换为CreateChild_DivElement,但是由于声明的函数未正确添加到接口(工具提示将值显示为任意值)而失败。

我希望为打字稿界面添加一个变量。

interface CustomElement<Original> {
   ...Original,
   createChild: createChild,
}

并像下面的示例一样使用它

declare function createChild(type: "div", options?: CreateChild_Options, node?: HTMLElement): CustomElement<HTMLDivElement>;

显然这是行不通的,仅是示例。

如何将声明的.createChild函数作为返回的HTMlElement的一部分。

浏览了一些未解决的打字稿问题后,我遇到了一个我不知道存在的类型声明。现在,我得到了完整的代码。可行,但绝对不是很漂亮。有没有更好的方法可以达到这个目的?

export = createChild;

// Declare the functions
declare function createChild(type: "div", options?: CreateChild_Options, node?: HTMLElement): CustomElement<HTMLDivElement>;
declare function createChild(type: "span", options?: CreateChild_Options, node?: HTMLElement): CustomElement<HTMLSpanElement>;
declare function createChild(type: "input", options?: CreateChild_Options, node?: HTMLElement): CustomElement<HTMLInputElement>;
declare function createChild(type: "p", options?: CreateChild_Options, node?: HTMLElement): CustomElement<HTMLParagraphElement>;
declare function createChild(type: "a", options?: CreateChild_Options, node?: HTMLElement): CustomElement<HTMLAnchorElement>;
declare function createChild(type: "img", options?: CreateChild_Options, node?: HTMLElement): CustomElement<HTMLImageElement>;
declare function createChild(type: "ul", options?: CreateChild_Options, node?: HTMLElement): CustomElement<HTMLUListElement>;
declare function createChild(type: "li", options?: CreateChild_Options, node?: HTMLElement): CustomElement<HTMLLIElement>;
declare function createChild(type: "hr", options?: CreateChild_Options, node?: HTMLElement): CustomElement<HTMLHRElement>;
declare function createChild(type: "h1" | "h2" | "h3" | "h4" | "h5" | "h6", options?: CreateChild_Options, node?: HTMLElement): CustomElement<HTMLHeadingElement>;
declare function createChild(type: string, options?: CreateChild_Options, node?: HTMLElement): CustomElement<HTMLElement>;

type CustomElement<Original> = Original & {
    createChild: ((type: "div", options?: CreateChild_Options, node?: HTMLElement) => CustomElement<HTMLDivElement>) &
    ((type: "span", options?: CreateChild_Options, node?: HTMLElement) => CustomElement<HTMLSpanElement>) &
    ((type: "input", options?: CreateChild_Options, node?: HTMLElement) => CustomElement<HTMLInputElement>) &
    ((type: "p", options?: CreateChild_Options, node?: HTMLElement) => CustomElement<HTMLParagraphElement>) &
    ((type: "a", options?: CreateChild_Options, node?: HTMLElement) => CustomElement<HTMLAnchorElement>) &
    ((type: "img", options?: CreateChild_Options, node?: HTMLElement) => CustomElement<HTMLImageElement>) &
    ((type: "ul", options?: CreateChild_Options, node?: HTMLElement) => CustomElement<HTMLUListElement>) &
    ((type: "li", options?: CreateChild_Options, node?: HTMLElement) => CustomElement<HTMLLIElement>) &
    ((type: "hr", options?: CreateChild_Options, node?: HTMLElement) => CustomElement<HTMLHRElement>) &
    ((type: "h1" | "h2" | "h3" | "h4" | "h5" | "h6", options?: CreateChild_Options, node?: HTMLElement) => CustomElement<HTMLHeadingElement>) &
    ((type: string, options?: CreateChild_Options, node?: HTMLElement) => CustomElement<HTMLElement>);
};

type ElementNames = 'div' | 'span' | 'input' | 'p' | 'i' | 'a' | 'img' | 'ul' | 'li' | 'hr' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';


/**
 * The options for create child
 */
interface CreateChild_Options {
    id?: string,
    classList?: string[],
    style?: CSSStyleDeclaration | string,
    childNodes?: (CreateChild_Create | CreateChild_Child)[],
    on: {
        click: (this: HTMLElement, ev: MouseEvent, options: boolean | AddEventListenerOptions) => any,
        contextmenu: (this: HTMLElement, ev: MouseEvent, options: boolean | AddEventListenerOptions) => any,
        keyup: (this: HTMLElement, ev: KeyboardEvent, options: boolean | AddEventListenerOptions) => any,
        keydown: (this: HTMLElement, ev: KeyboardEvent, options: boolean | AddEventListenerOptions) => any,
        keypress: (this: HTMLElement, ev: KeyboardEvent, options: boolean | AddEventListenerOptions) => any,
        focus: (this: HTMLElement, ev: FocusEvent, options: boolean | AddEventListenerOptions) => any,
        blur: (this: HTMLElement, ev: FocusEvent, options: boolean | AddEventListenerOptions) => any,
        focusin: (this: HTMLElement, ev: FocusEvent, options: boolean | AddEventListenerOptions) => any,
        focusout: (this: HTMLElement, ev: FocusEvent, options: boolean | AddEventListenerOptions) => any,
        [key: string]: (this: HTMLElement, ev: Event, options: boolean | AddEventListenerOptions) => any,
    }
};


/**
 * Used create child to create and append a new child element
 */
interface CreateChild_Create {
    type: ElementNames,
    options?: CreateChild_Options,
}


/**
 * appends a child element that was created already
 */
interface CreateChild_Child {
    child: HTMLElement | HTMLNode
}

1 个答案:

答案 0 :(得分:0)

包含函数声明的文件是一个模块。

模块是包含一个或多个顶级importexport语句的文件。

您的文件包含

export = createChild;

使其成为模块。

在模块中按词法指定的所有构造,无论它们的值或类型(是否为环境),都限于该模块。

但是,有时我们需要从模块内部伸出手,以便将某些东西添加到封闭的作用域中,对于模块来说,这就是全局作用域。

对于值,我们按照您所说的进行操作,并将其分配给windowglobalglobalThis的属性。当TypeScript将类型添加到JavaScript时,它需要一种语法来使我们能够对类型执行相同的操作。

该语法为declare global块。

在下面的代码中,该代码将应用于您的示例,

export = createChild;

declare global {
  function createChild(type: "div", options?: CreateChild_Options, node?: HTMLElement): CustomElement<HTMLDivElement>;
}