3

I have a project with Angular 6, Typescript, webpack 4.

I want to use alias in webpack in order to make my import statement clearer.

This is the code I have in webpack:

resolve: {
  alias: {
    assets: `${helpers.root('src/assets/')}`,
    app: `${helpers.root('src/app/')}`
  },
}

The "assets" alias is working fine !

I use the "app" alias in this way within the code of a component:

import { UtilsService } from 'app/_services/utils.service';

And this is the constructor of the component:

constructor( @Inject( UtilsService ) private utils: UtilsService, ) {
}

I don't have an error on the import statement, so I guess that the alias works in some way.

But I have the following error in the constructor:

TS2709: Cannot use namespace 'UtilsService' as a type.

I must be missing some configuration somewhere but can't figure out what ?

Any help will be greatly appreciated


EDIT: Following kemsky and David comment this is what I tried:

I added the following in tsconfig.json:

"baseUrl": ".",
"paths": {
  "@app": ["src/app/"] // This mapping is relative to "baseUrl"
}

I modify webpack.config.js to have:

resolve: {
  alias: {
    assets: `${helpers.root('src/assets/')}`,
    '@app': `${helpers.root('src/app/')}`
  },
}

And I tried to import using:

import { UtilsService } from 'app/_services/utils.service';

I still have the same error in the constructor of my component:

constructor( private utils: UtilsService, ) {}

TS2709: Cannot use namespace 'UtilsService' as a type.

If I change the import statement to something that don't exist, I have a the following error:

Module not found: Error: Can't resolve '@DONT_EXIST/_services/utils.service'

Which makes me think that the problem is with tsconfig.

Note:

I'm using awesome-typescript-loader, maybe it's linked, this is how I load tsconfig.json inside webpack.config.js

module: {
  rules: [
    {
      enforce: 'pre',
      test: /\.ts$/,
      use: [
        {
          loader: 'tslint-loader'
        }
      ]
    },

    {
      test: /\.ts$/,
      use: [
        {
          loader: '@angularclass/hmr-loader',
          options: {
            pretty: !isProd,
            prod: isProd
          }
        },
        {
          loader: 'ng-router-loader',
          options: {
            loader: 'async-import',
            genDir: 'compiled',
            aot: AOT
          }
        },
        {
          loader: 'awesome-typescript-loader',
          options: {
            configFileName: 'tsconfig.json',
            useCache: !isProd
          }
        },
        {
          loader: 'angular2-template-loader'
        }
      ],
      exclude: [/\.(spec|e2e)\.ts$/]
    },
Tonio
  • 4,082
  • 4
  • 35
  • 60
  • See example here https://github.com/angular/angular/issues/18484 probably you should also change tsconfig. – kemsky Jul 25 '18 at 12:46
  • Why do you need to specify `@Inject( UtilsService )`? How did you provide the service? – David Jul 26 '18 at 09:04
  • @David I don't really need to provide it, it works exactly the same if I don't write @Inject( UtilsService ). The question is more about the alias in webpack – Tonio Jul 26 '18 at 11:19
  • Oh ok I thought it was the inject causing the issue. So in your `utils.service` file you do export the `UtilsService` class correctly? If so, as suggested by @kemsky you could change tsconfig.json (insted of webpack) to declare the '@app' alias and try using the aliased import `import {UtilsService} from '@app/_services/utils.service;` – David Jul 26 '18 at 11:27
  • @David: See my edits, I tried but no luck. :-( – Tonio Jul 26 '18 at 14:13
  • Does it make a difference with `"@app/*": [ "src/app/*" ]` – David Jul 26 '18 at 14:31
  • Damn amazing, that made the difference !! No more error and I can use alias instead of having a bunch of ../../../.. for my import path. answer the question and I'll accept it. Amazing, thanks, I've been trying for ages – Tonio Jul 27 '18 at 08:40

1 Answers1

2

When defining path mappings, it's necessary to add '*' so that it works for all subpaths (as you are actually defining a pattern)

So your tsconfig.json should contain

"baseUrl": ".",
"paths": {
  "@app/*": ["src/app/*"] // This mapping is relative to "baseUrl"
}

That way, all modules matching @app/* such as

import {x}  from '@app/<moduleName>;

will resolve to

<baseUrl>/src/app/<moduleName>

More about module resolution here

David
  • 33,444
  • 11
  • 80
  • 118