javascript - 模块/命名空间的一般 TypeScript 用法

标签 javascript jquery typescript node-modules javascript-namespaces

我有一个使用 jQuery 和其他库的标准网页(不是使用 Angular、React、Vue 等呈现的应用程序)。

我想将良好实践与 TypeScript 集成。 做这个的最好方式是什么?

我当前的想法是有 3 个文件:

  1. index.d.ts(描述我的模块的类型)
  2. test.ts(index.d.ts 中描述的类型的实现)
  3. page.js(使用 test.js 中定义的 javascript 的文件 - test.ts 的输出)

我目前有以下内容:

index.d.ts

// Type definitions for test 1.0.0
// Project: Test
// Definitions by: Author Name

/// <reference path="../../lib/@types/jquery/index.d.ts" />
declare namespace TestNS {
    export class TestClass {
        // Fields
        element: JQuery;
        value: string;

        constructor(element: JQuery, val: string);

        OnCreate();

        static AttachToJQuery(jq: JQueryStatic): void;
    }

    interface JQuery {
        TestClass(element: JQuery, val?: string): TestNS.TestClass;
    }

    interface JQueryStatic {
        TestClass(element: JQuery, val?: string): TestNS.TestClass;
    }
}

Test.ts(第二次加载,在 jQuery 之后)

/// <reference path="../../lib/@types/jquery/index.d.ts" />
/// <reference path="./index.d.ts" />

export namespace TestNS {
    export class TestClass {
        // Fields
        element: JQuery;
        value: string;

        constructor(element: JQuery, val: string) {
            this.element = element;
            this.value = val;
            this.OnCreate();
        }

        OnCreate() {
            this.element.data('test-value', this.value);
        }

        static AttachToJQuery(jq: JQueryStatic) {
            //no jQuery around
            if (!jq) {
                return false;
            }

            jq.fn.extend({
                TestNS: function(newVal) {
                    return this.each(function() {
                        var obj = jq(this);
                        new TestNS.TestClass(obj, newVal);

                    });
                }
            });
        }//attach to jquery method (to easily work with noconflict mode)
    }//test class
}

page.js(最后加载)

let newJquery:JQueryStatic = jQuery.noConflict();
TestNS.TestClass.AttachToJQuery(newJquery);

let testElems = newJquery(".testClass");
testElems.TestClass();

我的目标是让我的代码整齐地组织到 typescript 中以及页面上的命名空间中(但在 typescript 中这样做会出现与重复标识符相关的错误)以及模块化和可扩展。我知道我应该在“node_modules/@types”目录下发布我的类型,但我现在只想将它们全部封装在这个模块中。

我尝试使用模块,并导入index.d.ts中定义的内容,但TypeScript说我无法导入该文件,并且找不到模块名称。我确实了解到,如果我使用一个模块,它应该附带一个加载器,例如 CommonJS、RequireJS 或 AMD,但我现在宁愿避免这样做(如果这样做不是一个可怕的做法,因为我想暂时降低复杂程度)。

我尝试过查看其他项目,但它们都使用加载器,这对于这种脚本来说似乎有点大材小用。

有什么好的方法可以解决这个问题吗?

最佳答案

如果您想让事情在没有模块加载器的情况下工作,您将必须进行一些更改。首先值得一提的是,TypeScript 支持两种主要的模块化代码方式:命名空间和模块。

注意:这里有点令人困惑的细微差别是关键字 namespacemodule 可以互换使用,并且它们本身不能确定一个事物是模块还是模块。命名空间。

1) 模块(以前称为外部模块) - 这些使用典型的导入、导出和 require 语义,并且需要模块加载器,最好是某种类型的 bundler 。对于这种模式,每个文件都被视为一个模块。任何包含导入或导出语句的文件都将被 TypeScript 编译器视为外部模块。

2) 命名空间(以前称为内部模块)- 此模式支持可以跨越多个文件的命名空间。如果您不想使用模块加载器,则需要使用此模块类型。这种模式的使用变得越来越不常见,但如果您出于某种原因想要使用它,它仍然是一种选择。要使用这种类型的模块化,文件中不能有任何导入或导出语句。

这是有关命名空间的文档 https://www.typescriptlang.org/docs/handbook/namespaces.html

假设您想遵循最初的计划,则需要在代码中进行一些调整。

1) 正如 @sbat 所提到的,您的 index.d.ts 正在重新声明您的命名空间和类类型。这可能会导致重复定义错误。您可以通过简单地覆盖 JQuery 接口(interface)来替换整个内容。

/** Extend the JQuery interface with custom method. */
declare interface JQuery {
    TestNS: () => TestNS.TestClass
}

2) 确保您没有任何顶级导出或导入。具体来说,您需要从 test.ts 中的命名空间中删除 export。这将使您的模块成为内部模块,而不是外部模块。

namespace TestNS {
    export class TestClass {
        ...
    }
}

关于javascript - 模块/命名空间的一般 TypeScript 用法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53528472/

相关文章:

javascript - 如何在sightly JAVA Script USE API中将对话框属性值传递给AJAX请求?

javascript - 在内部链接上,例如#id 是否有一个事件被触发,我可以附加一个处理程序?

javascript - 你如何在jquery中移动一个div元素

javascript - Visual Studio 2015 NodeJS/Typescript 覆盖 Node 启动文件

Angular 6 Form - 在 ValueChanges 之后改变值

angular 2 Routes 3.0,区分大小写

javascript - 内容完成渲染后动态设置 fancybox 2.1.4 iframe 的高度

javascript - 测试同构 javascript 应用程序

c# - 如何在JSTree中更改节点的新名称 "rename"

javascript - 将标签从输入更改为选择时,jQuery 代码中断