我有一个使用 jQuery 和其他库的标准网页(不是使用 Angular、React、Vue 等呈现的应用程序)。
我想将良好实践与 TypeScript 集成。 做这个的最好方式是什么?
我当前的想法是有 3 个文件:
- index.d.ts(描述我的模块的类型)
- test.ts(index.d.ts 中描述的类型的实现)
- 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 支持两种主要的模块化代码方式:命名空间和模块。
注意:这里有点令人困惑的细微差别是关键字 namespace
和 module
可以互换使用,并且它们本身不能确定一个事物是模块还是模块。命名空间。
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/