[英]Import classes from external typescript library which uses namespaces
我有一个现有的Angular 2项目,现在我必须使用一个使用命名空间的外部TypeScript库。 我不知何故需要从外部库导入一些类,以便我可以使用它们。
externalLibrary.ts :
namespace com.foo.bar {
export class A {
doSomething() {
}
}
}
在My Angular2组件中我想做:
myA: A = new A();
myA.doSomething();
到目前为止,我尝试过:
1)
import {A} from '../dir/externalLibrary';
这导致编译错误,因为它说:'externalLibrary.ts不是一个模块'。
2)
/// <reference path='../dir/externalLibrary.ts'>
...
myA: com.foo.bar.A = new com.foo.bar.A();
导致运行时错误说:'ReferenceError:com未定义'
我的问题是:如何在我的项目中使用A类? 我感谢任何帮助。
编辑1:
只是为了澄清:外部库是一个Java库,然后将其转换为TypeScript。 它由大约80,000行代码组成,因此我不能改变太多,因为它需要花费太多时间。 这也是我必须坚持命名空间的原因,因为Typescipt转换器从现有的java包结构中创建它们。
@Aaron:感谢您的回答,但我即将出现的'导出命名空间'方法问题如下:如果我在命名空间之前放置'export',则无法再找到其他类:
b.ts:
export namespace com.foo.bar
{
export interface B {
}
}
a.ts
export namespace com.foo.bar {
export class A implements B
{
}
}
在文件a.ts中,编译器说:'找不到名字B'。 我也试图以某种方式导入B但我失败了。 导入B是否有任何可能性,或者我完全是错误的方式?
这导致编译错误,因为它说:'externalLibrary.ts不是一个模块'。
这个编译错误似乎是事实。 看看你的定义它不是导出一个模块,它只是声明一个全局命名空间。 您可以使用导入别名 (TS功能,而不是ES6)来清理您的使用情况:
import A = com.foo.bar.A;
new A();
/// <reference path='../dir/externalLibrary.ts'>` myA: com.foo.bar.A = new com.foo.bar.A();
导致运行时错误说:'ReferenceError:com未定义'
这意味着您需要在运行的代码中实际包含已编译的externalLibrary.js
。 这可能就像<script>
标签一样简单,或者如果你使用的是捆绑器,你可以将文件作为副作用import "./dir/externalLibrary";
: import "./dir/externalLibrary";
如果您控制外部库(如果您这样做,我不清楚),那么您可以导出命名空间:
export namespace com.foo.bar { ... }
将其转换为模块(导出命名空间),您可以导入顶级命名空间:
import { com } from "../dir/externalLibrary";
const a: com.foo.bar.A = new com.foo.bar.A();
您无法直接导入A
,但仍可以使用导入别名:
import { com } from "../dir/externalLibrary";
import A = com.foo.bar.A;
const a: A = new A();
但在这一点上,我会说命名空间是没有意义的 。 只需从模块中导出类:
export class A { ... }
现在您可以直接导入并使用它:
import { A } from "../dir/externalLibrary";
const a = new A();
a.doSomething();
将文件转换为模块后(通过添加顶级export
),只有导出的成员在文件外部可见,并且必须由要使用的其他文件显式导入。
您已使用此前的示例更新了您的问题:
// a.ts
namespace com.foo.bar {
export class A implements B { }
}
// b.ts
namespace com.foo.bar {
export class B { }
}
在这种情况下,它正在做的是在全局范围内合并名称空间com.foo.bar
。 但是,一旦你制作了这些文件模块(通过添加export namespace
),那么它们不再是全局范围并且彼此不知道,除非它们明确地相互导入,所以A implements B
在上面不知道B
是什么。
你需要导入B
但是对于模块,你不能将导入的名称与本地声明的名称合并,所以我之前的示例导入{com}
将不起作用(当你将模块文件视为孤立的作用域时,它也没有意义,这就是它们是):
// a.ts
import { com } from "./b"; // import "com"
export namespace com.foo.bar { } // declare "com" -- Error: name conflict
您可以使用* as
通配符(基本上是ES6名称空间导入)导入其他文件以避免此冲突:
// a.ts
import * as b from "./b";
import B = b.com.foo.bar.B; // alias now starts with `b.`
export namespace com.foo.bar {
export class A implements B { }
}
我现在要说的是,生成此代码的格式已过时并导致与ES6模块的摩擦。 在ES6模块中使用名称空间被认为是不合时宜的 - 在ES6模块文件存在之前,它们自己定义范围,名称空间(在ES5中只是全局对象/函数闭包)是定义范围的一种方式。 使用ES6模块你真正想要的是文件结构足够,所以com/foo/bar/a.ts
本身就是范围,当你从该文件export class A
时,你就不会与任何东西发生冲突,即使A
由另一个文件导出,另一个文件是不同的范围。 消费者文件将通过文件路径import { A } from "./com/bar/a"
(或任何相对路径) import { A } from "./com/bar/a"
,如果需要避免名称与其他A
导入冲突,则可以由该导入文件处理使用as
。
也就是说,我理解重构代码生成以导出没有名称空间的惯用ES6模块可能不可行。 我会说你有两个选择:
回到使用全局命名空间(没有export namespace
)生成代码并解决构建问题,以便这些文件实际包含在构建中。 你没有在这里提到你的方法(只是你有一个运行时ReferenceError
,表明你的设置中没有包含该文件),但如果你能够使用ES6导入/导出我假设你正在使用模块捆绑器像Webpack或Rollup。 模块捆绑器旨在捆绑模块,因此包括一些全局代码可能是非常重要的 。 请记住,仅仅因为TypeScript可以编译它,并不意味着您的捆绑包知道如何捆绑它。
修改代码生成以export
名称空间,并使用* as
通配符import
所有文件,如上一个示例所示。
你也应该导出你的命名空间:
export namespace com.foo.bar { export class A { doSomething() { } } }
接着:
import * as comFooBar from '../dir/externalLibrary';
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.