Home > front end >  Is it possible to organize angular modules and component files with typscript namespaces?
Is it possible to organize angular modules and component files with typscript namespaces?

Time:05-24

For example below code is not working as expected. Let's say I have button namespace:

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;

and in app.module:

import Button from './button';

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

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

I'm getting this compilation error:

<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

What's more, how can I split the component and module into different files while still having them in the same namespace? I tried the following, but with no avail: https://www.typescriptlang.org/docs/handbook/namespaces.html#multi-file-namespaces

My point is to organize project with lots of components and modules. I have lot of files with very long names to describe its functionality, for example:

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

and I just wanted to make one namespace that wraps each functionality, just like this:

-> 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

And so on for every other functionality. I was just thinking about reducing boilerplate in file names and it's also good for IDE intellisense because components inside namespaces are encapsulated and hidden.

CodePudding user response:

Typescript namespaces are essentially obsolete at this point. TypeScript had the concept before ES modules were added to ES6. TypeScript's design goals are to keep the language in sync with ECMA where possible, so while it might have a feature before ECMA does, it will favor the native implementation if one is later added. TypeScript's "external modules" are now largely indistinguishable from ES modules and are sufficient for both use cases. See https://www.typescriptlang.org/docs/handbook/namespaces-and-modules.html#needless-namespacing

The behavior you're looking for is the purpose of an index.ts file. Typically, when a given directory has an index.ts, it means that the other contents of the directory are "internal" (i.e. not used by anything outside of the directory), and the things exported from the index are the "external module".

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

The index.ts would generally look something like:

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

For the behavior in your question, you can import the entire module into a variable like:

import * as Button from './button';

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

However, it's more common to just import the specific members needed like:

import { ButtonModule } from './button';

You certainly can do it either way, but the former is more idomatic, as evidenced by the CommonModule or AppRoutingModule used in the same place. The explicit namespacing is simply unnecessary, as there is no ambiguity in the source of the import.


The import * as syntax is convenient in a handful of cases where something exports a large number of things that you use all together, but the typical use case for that is a module that exports a group closely related functions, not a bunch of types. E.g.

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);

It's indistinguishable from an api.ts that exports an object with all of those methods, but is convenient to organize the code in separate files.

  • Related