【问题标题】:In typescript how do I extend a global interface with a declared function在打字稿中,如何使用声明的函数扩展全局接口
【发布时间】:2020-07-21 09:43:44
【问题描述】:

我正在处理一个遗留的 javascript 项目,目前正在为一些更流行的函数添加 typescript 声明 .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
}

我会用CreateChild_DivElement 替换HTMLDivElement,但由于声明的函数没有正确添加到界面而失败(工具提示显示任何值)

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

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
}

【问题讨论】:

  • 在一个模块中,一个包含顶级importexport 的文件,所有声明都限定在该模块的范围内。为了在模块中声明像 createChild 这样的环境全局变量,TypeScript 提供了 declare global 构造。例如:import x from 'y'; declare global { function createChild(type: "div", ...) }
  • @AluanHaddad 我似乎听不懂你在说什么。我认为声明一个全局是向窗口/全局范围添加一个变量。在这种情况下,我似乎无法弄清楚如何使用全局变量。
  • 我举个例子

标签: typescript typescript-typings


【解决方案1】:

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

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

您的文件包含

export = createChild;

使它成为一个模块。

在模块中以词法方式指定的所有构造,无论它们是值还是类型,无论环境与否,都在该模块的范围内。

但是,有时我们需要从模块中伸出手来向封闭范围添加一些东西,对于模块来说,这就是全局范围。

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

该语法是declare global 块。

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

export = createChild;

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

【讨论】:

    猜你喜欢
    • 2016-03-27
    • 2017-10-22
    • 1970-01-01
    • 2019-05-04
    • 1970-01-01
    • 2021-02-17
    • 1970-01-01
    • 2022-01-20
    相关资源
    最近更新 更多