简体   繁体   English

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

[英]Import classes from external typescript library which uses namespaces

I have an existing Angular 2 Project and now I have to use an external TypeScript Library which uses Namespaces. 我有一个现有的Angular 2项目,现在我必须使用一个使用命名空间的外部TypeScript库。 I somehow need to import some classes from the External library so I can use them. 我不知何故需要从外部库导入一些类,以便我可以使用它们。

externalLibrary.ts : externalLibrary.ts

namespace com.foo.bar {

  export class A {
    doSomething() {
    }
  }
}

And in My Angular2 Component I want to to do: 在My Angular2组件中我想做:

myA: A = new A();
myA.doSomething(); 

So far, i have tried: 到目前为止,我尝试过:

1) 1)

import {A} from '../dir/externalLibrary';

which results in a compilation error because it says: 'externalLibrary.ts is not a module'. 这导致编译错误,因为它说:'externalLibrary.ts不是一个模块'。

2) 2)

/// <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' 导致运行时错误说:'ReferenceError:com未定义'

My Question is: How can I use the class A in my Project? 我的问题是:如何在我的项目中使用A类? I am thankful for any help. 我感谢任何帮助。

EDIT 1: 编辑1:

Just for clarification: The external library is a Java Library which is then transpiled into TypeScript. 只是为了澄清:外部库是一个Java库,然后将其转换为TypeScript。 It consists of ~80.000 lines of code, therefore I can not change too much, because it would take too much time. 它由大约80,000行代码组成,因此我不能改变太多,因为它需要花费太多时间。 This is also the reason why I have to stick to namespaces because the Typescipt transpiler creates them out of the existing java package structure. 这也是我必须坚持命名空间的原因,因为Typescipt转换器从现有的java包结构中创建它们。

@Aaron: Thanks for the answer but my upcoming problem with the 'export namespace' approach is as follows: If i put 'export' before a namespace other Classes can not be found any longer: @Aaron:感谢您的回答,但我即将出现的'导出命名空间'方法问题如下:如果我在命名空间之前放置'export',则无法再找到其他类:

b.ts: b.ts:

export namespace com.foo.bar 
{
    export interface B {

    }
}

a.ts a.ts

export namespace com.foo.bar {

    export class A implements B
    {

    }
}

In file a.ts the compiler says: 'cannot find name B'. 在文件a.ts中,编译器说:'找不到名字B'。 I also tried to somehow import B but I failed. 我也试图以某种方式导入B但我失败了。 Is there any posibillity to import B or am I completely on the wrong way? 导入B是否有任何可能性,或者我完全是错误的方式?

which results in a compilation error because it says: 'externalLibrary.ts is not a module'. 这导致编译错误,因为它说:'externalLibrary.ts不是一个模块'。

This compile error appears to be the truth. 这个编译错误似乎是事实。 Looking at your definition it isn't exporting a module, it's just declaring a global namespace. 看看你的定义它不是导出一个模块,它只是声明一个全局命名空间。 You can use an import alias (TS feature, not ES6) to clean up your usage a bit: 您可以使用导入别名 (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' 导致运行时错误说:'ReferenceError:com未定义'

This means you need to actually include the compiled externalLibrary.js in your running code. 这意味着您需要在运行的代码中实际包含已编译的externalLibrary.js That could be as simple as a <script> tag, or if you're using a bundler you might be able to import the file as a side-effect: import "./dir/externalLibrary"; 这可能就像<script>标签一样简单,或者如果你使用的是捆绑器,你可以将文件作为副作用import "./dir/externalLibrary";import "./dir/externalLibrary";

If you control the external library (not clear to me if you do) then you can export the namespace: 如果您控制外部库(如果您这样做,我不清楚),那么您可以导出命名空间:

export namespace com.foo.bar { ... }

Which turns it into a module (that exports a namespace), and you can import the top level namespace: 将其转换为模块(导出命名空间),您可以导入顶级命名空间:

import { com } from "../dir/externalLibrary";
const a: com.foo.bar.A = new com.foo.bar.A();

You can't import A directly, but you can still use an import alias: 您无法直接导入A ,但仍可以使用导入别名:

import { com } from "../dir/externalLibrary";
import A = com.foo.bar.A;
const a: A = new A();

But at this point I would say the namespace is pointless . 但在这一点上,我会说命名空间是没有意义的 Just export the class from your module: 只需从模块中导出类:

export class A { ... }

Now you can import it directly and use it: 现在您可以直接导入并使用它:

import { A } from "../dir/externalLibrary";
const a = new A();
a.doSomething();

Edit 编辑

Once you turn a file into a module (by adding a top-level export ) then only exported members are visible outside the file, and they must be explicitly imported by other files to be used. 将文件转换为模块后(通过添加顶级export ),只有导出的成员在文件外部可见,并且必须由要使用的其他文件显式导入。

You've updated your question with this example that you previously had: 您已使用此前的示例更新了您的问题:

// a.ts
namespace com.foo.bar {
    export class A implements B { }
}
// b.ts
namespace com.foo.bar {
   export class B { }
}

In this case what it was doing is merging namespaces com.foo.bar in global scope. 在这种情况下,它正在做的是在全局范围内合并名称空间com.foo.bar However, once you make these files modules (by adding export namespace ) then they are no longer in global scope and are unaware of each other unless they explicitly import each other, so A implements B in the above doesn't know what B is anymore. 但是,一旦你制作了这些文件模块(通过添加export namespace ),那么它们不再是全局范围并且彼此不知道,除非它们明确地相互导入,所以A implements B在上面不知道B是什么。

You need to import B . 你需要导入B But with modules, you can't merge an imported name with a local declared name, so my previous example importing {com} won't work (nor does it make sense when you think of module files as isolated scopes, which is what they are): 但是对于模块,你不能将导入的名称与本地声明的名称合并,所以我之前的示例导入{com}将不起作用(当你将模块文件视为孤立的作用域时,它也没有意义,这就是它们是):

// a.ts
import { com } from "./b"; // import "com"
export namespace com.foo.bar { } // declare "com" -- Error: name conflict

You could import the other file using a * as wildcard (basically an ES6 namespace import) to avoid this collision: 您可以使用* 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 { }
}

I'm just going to say right now that the format this code is generated in is outdated and causing friction with ES6 modules. 我现在要说的是,生成此代码的格式已过时并导致与ES6模块的摩擦。 Using namespaces in an ES6 module is considered mostly anachronistic -- before ES6 module files existed, which themselves define scopes, namespaces (in ES5 just global objects/function closures) were a way to define scope. 在ES6模块中使用名称空间被认为是不合时宜的 - 在ES6模块文件存在之前,它们自己定义范围,名称空间(在ES5中只是全局对象/函数闭包)是定义范围的一种方式。 With ES6 modules what you really want is for your file structure to be enough, so com/foo/bar/a.ts is itself the scope, and when you export class A from that file, you are not conflicting with anything, even if A is exported by another file, that other file is a different scope. 使用ES6模块你真正想要的是文件结构足够,所以com/foo/bar/a.ts本身就是范围,当你从该文件export class A时,你就不会与任何东西发生冲突,即使A由另一个文件导出,另一个文件是不同的范围。 Consumer files will import by the file path import { A } from "./com/bar/a" (or whatever the relative path is), and if necessary to avoid name conflicts with other A imports it can be handled by that importing file using as . 消费者文件将通过文件路径import { A } from "./com/bar/a" (或任何相对路径) import { A } from "./com/bar/a" ,如果需要避免名称与其他A导入冲突,则可以由该导入文件处理使用as

That said, I understand refactoring your code generation to export idiomatic ES6 modules without namespaces might not be feasible. 也就是说,我理解重构代码生成以导出没有名称空间的惯用ES6模块可能不可行。 I would say you have two options: 我会说你有两个选择:

  1. Go back to generating code using global namespaces (no export namespace ) and resolve your build issue so those files are actually included in the build. 回到使用全局命名空间(没有export namespace )生成代码并解决构建问题,以便这些文件实际包含在构建中。 You haven't mentioned your method here (only that you got a runtime ReferenceError , indicating the file is not being included in your setup), but if you're able to use ES6 import/export I assume you're using a module bundler like Webpack or Rollup. 你没有在这里提到你的方法(只是你有一个运行时ReferenceError ,表明你的设置中没有包含该文件),但如果你能够使用ES6导入/导出我假设你正在使用模块捆绑器像Webpack或Rollup。 Module bundlers are designed to bundle modules so including some global code can be surprisingly non-trivial . 模块捆绑器旨在捆绑模块,因此包括一些全局代码可能是非常重要的 Remember that just because TypeScript can compile it, doesn't mean your bundler knows how to bundle it. 请记住,仅仅因为TypeScript可以编译它,并不意味着您的捆绑包知道如何捆绑它。

  2. Modify the code generation to export the namespaces, and import in all files using * as wildcards, as in my last example. 修改代码生成以export名称空间,并使用* as通配符import所有文件,如上一个示例所示。

you should export your namespace too: 你也应该导出你的命名空间:

 export namespace com.foo.bar { export class A { doSomething() { } } } 

and then: 接着:

import * as comFooBar from '../dir/externalLibrary';

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM