是否可以使用打字稿命名空间来组织 angular 模块和组件文件?

Is it possible to organize angular modules and component files with typscript namespaces?

例如,下面的代码没有按预期工作。假设我有按钮命名空间:

namespace Button {

  @Component({
    selector: 'super-button',
    templateUrl: './button.component.html',
    styleUrls: ['./button.component.scss']
  })
  export class ButtonComponent {}

  @NgModule({
    declarations: [
      ButtonComponent
    ],
    imports: [
      CommonModule
    ],
    exports: [ButtonComponent]
  })
  export class ButtonModule { }

}
 
export default Button;

并在 app.module 中:

import Button from './button';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,

    Button.ButtonModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

我遇到这个编译错误:

<e> [webpack-dev-middleware] Error: [object Object]
<e>     at analyzingFileEmitter (E:\Projects\Angular\test-app\node_modules\@ngtools\webpack\src\ivy\plugin.js:452:23)
<e>     at processTicksAndRejections (node:internal/process/task_queues:96:5)
<e>     at async AngularWebpackPlugin.rebuildRequiredFiles (E:\Projects\Angular\test-app\node_modules\@ngtools\webpack\src\ivy\plugin.js:277:36)
<e>     at async E:\Projects\Angular\test-app\node_modules\@ngtools\webpack\src\ivy\plugin.js:218:17

此外,如何将组件和模块拆分到不同的文件中,同时仍将它们放在同一个命名空间中? 我尝试了以下,但无济于事: https://www.typescriptlang.org/docs/handbook/namespaces.html#multi-file-namespaces

我的观点是组织包含大量组件和模块的项目。我有很多名称很长的文件来描述它的功能,例如:

-> very-descriptive-A-list.module
-> very-descriptive-A-list.component
-> very-descriptive-A-list-item.component
-> very-descriptive-A-list-modal.component etc

我只是想创建一个包装每个功能的命名空间,就像这样:

-> very-describtive-A namespace:
->> list.module,
->> list.component,
->> item.component
->> modal.component etc

-> very-describtive-B namespace:
->> list.module,
->> list.component,
->> item.component
->> modal.component etc

其他所有功能依此类推。我只是想减少文件名中的样板文件,这对 IDE 智能感知也有好处,因为命名空间内的组件被封装和隐藏了。

Typescript 命名空间在这一点上基本上已经过时了。在 ES 模块加入 ES6 之前,TypeScript 就有这个概念。 TypeScript 的设计目标是尽可能使语言与 ECMA 保持同步,因此虽然它可能具有 ECMA 之前的功能,但如果稍后添加,它将支持本机实现。 TypeScript 的“外部模块”现在在很大程度上与 ES 模块没有区别,并且足以满足这两种用例。参见 https://www.typescriptlang.org/docs/handbook/namespaces-and-modules.html#needless-namespacing

您正在寻找的行为是 index.ts 文件的目的。通常,当给定的目录有一个 index.ts 时,这意味着该目录的其他内容是“内部的”(即不被目录外的任何东西使用),而从索引导出的东西是“外部的”模块”。

button
├── button-component.ts
├── button-module.ts
└── index.ts

index.ts 通常类似于:

export { ButtonComponent } from './button-component';
export { ButtonModule } from './button-module';

对于您问题中的行为,您可以将整个模块导入到一个变量中,例如:

import * as Button from './button';

// ...
imports: [
  Button.ButtonModule,

但是,更常见的做法是仅导入所需的特定成员,例如:

import { ButtonModule } from './button';

你当然可以做这两种方式,但前者更惯用,正如在同一个地方使用的CommonModuleAppRoutingModule所证明的那样.显式命名空间完全没有必要,因为 import.

的来源没有歧义

import * as 语法在少数情况下很方便,在这种情况下,某些东西会导出大量您一起使用的东西,但典型的用例是导出一个密切相关的组的模块 函数,而不是一堆类型。例如

api/
├── create-user.ts
├── delete-user.ts
├── get-user.ts
├── index.ts
└── update-user.ts
import * as api from './api';

// ...
await api.getUser(123);
await api.deleteUser(123);

它与导出具有所有这些方法的对象的 api.ts 没有区别,但是将代码组织在单独的文件中很方便。