gpt4 book ai didi

angular - 从使用命名空间的外部 typescript 库导入类

转载 作者:行者123 更新时间:2023-12-04 16:53:17 24 4
gpt4 key购买 nike

我有一个现有的 Angular 2 项目,现在我必须使用一个使用命名空间的外部 TypeScript 库。我不知何故需要从外部库中导入一些类,以便我可以使用它们。

externalLibrary.ts :

namespace com.foo.bar {

export class A {
doSomething() {
}
}
}

在我的 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 is not defined'

我的问题是:如何在我的项目中使用 A 类?
我很感激任何帮助。

编辑 1:

只是为了澄清:外部库是一个 Java 库,然后被转换为 TypeScript。它由大约 80.000 行代码组成,因此我不能更改太多,因为这会花费太多时间。这也是我必须坚持使用命名空间的原因,因为 Typescipt 转译器从现有的 java 包结构中创建它们。

@Aaron:感谢您的回答,但我即将遇到的“导出命名空间”方法问题如下:
如果我将“导出”放在命名空间之前,则无法再找到其他类:

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 或者我完全走错了路?

最佳答案

which results in a compilation error because it says: 'externalLibrary.ts is not a module'.



这个编译错误似乎是事实。查看您的定义,它不是导出模块,它只是声明了一个全局命名空间。您可以使用 import alias (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();

which results in a run-time error saying: 'ReferenceError: com is not defined'



这意味着您需要实际包含已编译的 externalLibrary.js在您的运行代码中。这可能就像 <script> 一样简单标签,或者如果您使用的是打包器,您可以将文件作为副作用导入: 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();

但在这一点上我会说 the namespace is pointless .只需从您的模块中导出类:
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 模块中使用命名空间是 considered mostly anachronistic -- 在 ES6 模块文件存在之前,它们本身定义了作用域,命名空间(在 ES5 中只是全局对象/函数闭包)是定义作用域的一种方式。使用 ES6 模块,您真正想要的是文件结构足够,所以 com/foo/bar/a.ts本身就是范围,当你 export class A从该文件中,您不会与任何内容发生冲突,即使 A由另一个文件导出,该另一个文件是不同的范围。消费者文件将按文件路径 import { A } from "./com/bar/a" 导入(或任何相对路径),并在必要时避免与其他 A 发生名称冲突。导入它可以由使用 as 的导入文件处理.

也就是说,我理解重构您的代码生成以导出没有命名空间的惯用 ES6 模块可能是不可行的。我会说你有两个选择:
  • 返回使用全局命名空间(没有 export namespace)生成代码并解决您的构建问题,以便这些文件实际上包含在构建中。您没有在这里提到您的方法(只是您有一个运行时 ReferenceError ,表明该文件未包含在您的设置中),但是如果您能够使用 ES6 导入/导出,我假设您使用的是模块打包器,如 Webpack 或 Rollup。模块捆绑器旨在捆绑模块,因此可以包含一些全局代码 surprisingly non-trivial .请记住,仅仅因为 TypeScript 可以编译它,并不意味着您的捆绑器知道如何捆绑它。
  • 修改代码生成为export命名空间,以及 import在所有文件中使用 * as通配符,就像我上一个例子一样。
  • 关于angular - 从使用命名空间的外部 typescript 库导入类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47655725/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com