typescript 如何跨角度模块正确导入/导出类?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/49060157/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 05:15:44  来源:igfitidea点击:

How to properly import/export classes across angular modules?

angulartypescriptecmascript-6

提问by mdarefull

This question comes from the context of Enterprise Application.

这个问题来自企业应用程序的上下文。

From all the books I've read and online samples I've seen about angular applications, each time we create a class (component, service, entity, etc.) we export them on the type definition and then directly import them wherever we require a reference (similar to using namespaces on C#) regardless both classes belongs to the same or distinct angular modules.

从我读过的所有书籍和我看过的关于 Angular 应用程序的在线示例中,每次我们创建一个类(组件、服务、实体等)时,我们都会在类型定义上导出它们,然后在需要的地方直接导入它们一个引用(类似于在 C# 上使用命名空间),无论两个类属于相同还是不同的 angular 模块。

Ex:

前任:

// In 'Commons/logger.service.ts'
export class LoggerService { ... }

// In 'Core/common.service.ts'
export class CommonService { ... }

// In 'Products/' module
import { LoggerService } from '../Commons/logger.service'
import { CommonService } from '../Core/common.service'

export class ProductComponent { ... }

I started working on a (big) enterprise application project and noticed an approach I had never seen before, they created files to gather each type of class (service, entity, method parameter, component) exporting each one of them, export each one of these files on its corresponding angular module file and then, instead of importing the type directly from the type's file, perform the importing from the given module.

我开始研究一个(大)企业应用程序项目并注意到一种我以前从未见过的方法,他们创建文件来收集每种类型的类(服务、实体、方法参数、组件),导出它们中的每一个,导出每一个这些文件位于其相应的 angular 模块文件中,然后,不是直接从类型文件导入类型,而是从给定模块执行导入。

The previous example would be transformed to something like this:

前面的示例将转换为如下所示:

// In 'Commons/logger.service.ts'
export class LoggerService { ... }

// In 'Commons/services.ts'
export * from './logger.service.ts'
export * from './other.service.ts'
export * from './another.service.ts'

// In 'Commons/commons.module.ts'
export * from 'services.ts'
export * from 'entities.ts'
/* ... */


// In 'Products/' module
import { LoggerService, OtherService } from '../Commons/commons.module'

export class ProductComponent { ... }

Given that this approach is much more verbose than the one before and that it provokes awkward results in some cases (cyclic reference warning if importing classes within the same module)

鉴于这种方法比以前的方法要冗长得多,并且在某些情况下会引起尴尬的结果(如果在同一模块中导入类,则会出现循环引用警告)

My questions are:

我的问题是:

  1. Which approach is recommended, from a good design or best practices perspective?
  2. Is this approach recommended over the former? Why? For which cases?
  3. Why this approach isn't introduced on the major sources of documentation (angular online docs, angular books, ...)?
  4. What are the pros and cons of this approach.
  1. 从好的设计或最佳实践的角度来看,推荐哪种方法?
  2. 这种方法是否优于前者?为什么?适用于哪些情况?
  3. 为什么在主要的文档来源(angular 在线文档、angular 书籍等)中没有引入这种方法?
  4. 这种方法的优缺点是什么。

回答by Daniel W Strimpel

This is a concept known as a barrel file. These files make importing classes more convenient. It isn't a concept to Angular alone. It seems to be a best practice in TypeScript to use them.

这是一个称为桶形文件的概念。这些文件使导入类更加方便。这不仅仅是 Angular 的概念。在 TypeScript 中使用它们似乎是最佳实践。

When you have a smaller project, you may not see much of a benefit of creating these files, but they come in to be super helpful when working on larger projects with multiple team members. Below are some of the pros/cons that I'm aware of.

当您有一个较小的项目时,您可能看不到创建这些文件的太多好处,但是在有多个团队成员的大型项目中工作时,它们会非常有用。以下是我所知道的一些优点/缺点。

Pro: Less Knowledge Needed Around Module Internals

优点:模块内部所需的知识较少

When a component needs to have a reference to something, it shouldn't have to know what exact file the class, etc. is in. When you don't barrel the stuff within a module then every other file outside of the module will need to know exactly what file (including the sub path) contains that item. If you barrel the items up into a single module barrel, you simply need to know what module it is from. This also gives you the benefit of refactoring a module not requiring you to make sure the path gets updated if the file moves (your tooling may or may not help out with this).

当一个组件需要引用某些东西时,它不应该知道类等在哪个文件中。确切知道哪个文件(包括子路径)包含该项目。如果您将物品放入单个模块桶中,您只需要知道它来自哪个模块。这也为您提供了重构模块的好处,不需要您确保在文件移动时更新路径(您的工具可能会也可能不会对此有所帮助)。

// without barrel files
import { Class1 } from 'app/shared/module1/subpath1/subpath2/class1.service';

// using barrel files
import { Class1 } from 'app/shared/module1';

Pro: Explicit Exporting Outside Module

Pro:显式导出外部模块

Another benefit is that a module may contain a bunch of classes, interfaces, etc. that really are only meant to be used within that module. By creating a barrel file for a module, you are letting other devs know what is meant to be used outside of the module. Additionally, you are letting them know exactly what items there are to be used, so they don't need to hunt around to find an interface that they need (again, your tooling may or may not assist in this).

另一个好处是一个模块可能包含一堆类、接口等,这些类、接口等实际上只能在该模块中使用。通过为模块创建桶文件,您可以让其他开发人员知道在模块之外使用什么。此外,您要让他们确切地知道要使用哪些项目,因此他们无需四处寻找所需的界面(同样,您的工具可能会也可能不会对此提供帮助)。

// export these items from module as others need to have references to these
export { ExampleModule } from './example.module';
export { ExampleService } from './example.service';
export { ExampleInterface } from './example.model';

// these also exist in module but others don't need to know about them
// export { ExampleComponent } from './example.component';
// export { Example2Service } from './example2.service';
// export { ExampleInterface2 } from './example.model';

Pro: Cleaner Imports

优点:更清洁的进口

The final benefit I'll mention is that it helps to clean up your imports. Not only does it make it more clear what items come from what modules, it also helps to make the fromportion of your import much shorter as you don't need to traverse down sub directories, etc. As a note, the best practice seems to be to have the barrel file be index.tsin a folder since the TypeScript compiler will look for that file as default when given a folder to import from.

我要提到的最后一个好处是它有助于清理您的导入。它不仅更清楚哪些项目来自哪些模块,它还有助于使from导入的部分更短,因为您不需要遍历子目录等。请注意,最佳实践似乎是将桶文件index.ts放在一个文件夹中,因为当给定要从中导入的文件夹时,TypeScript 编译器会默认查找该文件。

// without barrel files (hopefully they would be not randomly ordered to make it even harder...)
import { Class1 } from 'app/shared/module1/subpath1/subpath2/class1.service';
import { Class2 } from 'app/shared/module1/subpath1/class2.component';
import { Interface1 } from 'app/shared/module1/module1.model';
import { Class3} from 'app/shared/module2/subpath3/class3.service';
import { Interface2 } from 'app/shared/module2/module2.model';

// using barrel files
import { Class1, Class2, Interface1 } from 'app/shared/module1';
import { Class3, Interface2 } from 'app/shared/module2';

Con: Additional File

缺点:附加文件

In trying to identify the cons, the only thing that I can think of is that you are creating another file for each module (or maybe sub folder depending on how you want to do it). It has no run-time or compile-time effect as far as I am aware though.

在尝试确定缺点时,我唯一能想到的是您正在为每个模块创建另一个文件(或者可能是子文件夹,具体取决于您的操作方式)。据我所知,它没有运行时或编译时的影响。