julianobrasil
julianobrasil

Reputation: 9377

Typescript import alias + barrel file

I spent a lot of time recently because of a particular behavior of something (and I could not identify the possible root cause) in angular/ngrx/typescript ecosystem.

The scenario: I've built up some effects and I have exported them in a barrel file (index.ts):

import {MyEffects} from './my.effects';

export const effects: any[] = [
  MyEffects,
];

Then, in another barrel file, one level up in my directory structure, I have:

import * as EFFECTS from './effects'
export {EFFECTS};
-store
 |-index.ts   <= export {EFFECTS}
 |-effects
   |-index.ts
   |-my.effects.ts

And, finally, in the NgModule's imports array:

  [
   ...
   EffectsModule.forFeature(EFFECTS.effects),
   ...
  ]

When I tried to compile this, I got a way too short error message:

ERROR in params.map is not a function

And nothing more. And it prevented my project from compiling. And more... if I run ng serve the error also occurred, but if I changed anything while ng serve was watching for files changes, it simply recompiled the project successfully.

After an entire day looking for what could possibly be causing it, I figured out that the alias part wasn't doing what I thought it should do. Then, I've changed a little bit the structure and it's now working as expected

SOLUTION:

In the first barrel file:

import {MyEffects} from './my.effects';

export const EFFECTS: any[] = [
  MyEffects,
];

In the up-level barrel file:

export * from './effects'

// instead of:
// import * as SOMETHING from './effects'
// export {SOMETHING};

And in the NgModel:

  [
   ...
   EffectsModule.forFeature(EFFECTS),
   ...
  ]

But... why???

Am I misunderstanding any part of this process?

I'm not sure if this is important, but the feature that is registering the effects is lazy loaded.

Upvotes: 3

Views: 2353

Answers (1)

Christian Vincenzo Traina
Christian Vincenzo Traina

Reputation: 10444

You are creating a weird hierarchy. export * and import/export don't behave in the same way.

When you use export *, TypeScript behaves like all the exported symbols in that file are actually inside the file, even if they were imported from elsewhere. In other words, that module is just a transparent level in the hierarchy and it's only useful for shortening the paths (you will be able to write import {foo} from './module' in place of import {foo} from './module/src/foo).

Instead, when you use something like:

import * as smth from './path';
export {smth}

You are introducing a further level that wasn't there before. And it is the smth keyword. You won't get rid of the smth key, it's there and it's now wrapping your whole module.

Going back to your example, you should edit your question showing how you import Effects in your NgModule. If you imported it like:

import * as effects from './effects.ts';

Then you're introducing again a new symbol that wraps all the variables, so the correct path will be effects.effects.effects.etc.

Using destructuring and export *, instead, will let you import and export variables without creating wrappers.

The question now is, why didn't the compiler warn you? Because the typescript compiler is usually good at catching these types of problems. The solution is likely here:

export const effects: any[] = [

Remove the type definition (any[]) and let TypeScript interfere the type, I'm pretty sure it will show you the error that you were missing.

Upvotes: 1

Related Questions