我有一个使用jQuery和其他库的标准网页(不是使用angular,react,vue等渲染的应用程序)。
我想将优良作法与TypeScript集成在一起。 做这个的最好方式是什么?
我当前的想法是拥有3个文件:
我目前有以下内容:
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();
我的目标是将我的代码整齐地组织在打字稿中以及在页面上的命名空间中(但是在打字稿中这样做会产生与重复标识符有关的错误),并且具有模块化和可扩展性。我知道我应该将我的类型发布在“ node_modules / @ types”目录下,但是我现在只是希望它们都封装在此模块中。
我尝试使用模块,并导入index.d.ts中定义的内容,但是TypeScript说我无法导入此文件,并且找不到模块名称。我确实了解到,如果我使用模块,则应将其与诸如CommonJS,RequireJS或AMD的加载器一起使用,但是我现在最好避免这样做(如果这样做不是一种可怕的做法,我想暂时将复杂度降至最低)。
我尝试查看其他项目,但是它们都使用加载器,对于这种脚本来说似乎有点过分了。
是否有解决此问题的好方法?
答案 0 :(得分:4)
如果要在没有模块加载器的情况下使事情正常运行,则必须进行一些更改。首先,值得一提的是TypeScript支持两种主要的模块化代码,名称空间和模块的方式。
注意:这里有一个令人困惑的细微差别,就是关键字namespace
和module
可以互换使用,而不能单独确定事物是模块还是命名空间。
1)模块(以前称为外部模块)-这些模块使用典型的导入,导出,并且需要语义,并且需要模块加载器,最好是某种捆绑器。对于此模式,每个文件都被视为一个模块。包含任何导入或导出语句的任何文件都将被TypeScript编译器视为外部模块。
2)命名空间(以前称为内部模块)-此模式支持可以跨越多个文件的命名空间。如果您不想使用模块加载器,则这是您需要使用的模块类型。这种模式的使用变得不那么普遍了,但是如果您出于任何原因想要使用它,它仍然是一个选择。要使用这种类型的模块化,文件中不能包含任何导入或导出语句。
以下是namespaces
https://www.typescriptlang.org/docs/handbook/namespaces.html
假设您想使用原始计划,则需要在代码中进行一些调整。
1)如@sbat所述,您的index.d.ts
正在重新声明您的名称空间和类类型。这可能会导致重复的定义错误。您可以使用JQuery接口的简单覆盖替换全部内容。
/** Extend the JQuery interface with custom method. */
declare interface JQuery {
TestNS: () => TestNS.TestClass
}
2)确保没有任何顶级出口或进口。具体来说,您将要从export
中的命名空间中删除test.ts
。这将使您的模块成为internal
的模块,而不是external
的模块。
namespace TestNS {
export class TestClass {
...
}
}
答案 1 :(得分:1)
假设您只是想在一个简单的项目中尝试TypeScript,建议您简化一下操作:
删除index.d.ts。定义文件描述了现有的javascript代码,因此TypeScript可以识别其中的类型。您的项目中没有这种情况,无需重复测试中已有的类型信息。可以安全地删除此文件。
只需将您的test.ts构建到test.js中。确保您的jquery .d.ts位于应有的位置。
删除page.js,只需对test.ts中的所有代码进行编码即可进行测试。一旦使它起作用,就可以对其进行重组。
但是,如果您的目标是使代码模块化和可扩展,则建议的方法是确实使用模块:
从ECMAScript 2015开始,模块是 语言,并且应由所有兼容引擎支持 实现。因此,对于新项目,模块将是 推荐的代码组织机制。
https://www.typescriptlang.org/docs/handbook/namespaces-and-modules.html
要在浏览器的生产环境中使用模块,您将需要:
捆绑器。该工具将调用TypeScript来构建您的单个TS模块,然后将构建输出组合到单个javascript文件中。然后,您将把这个文件包含到HTML中。 WebPack可能是最容易启动的:https://webpack.js.org/concepts/
包装管理器。安装和管理第三方模块版本的工具。 https://www.npmjs.com/
这是一个值得研究的大领域,但我认为这不是一个过度的选择。如果您的代码是模块化的(即使只是2个模块),则需要一种基础结构来以一种方式捆绑和加载模块。有几种具有不同利益和取舍的选择,但是从根本上来说,这是没有办法的。