Angular2 - leveraging root-relative imports

Having trouble with imports in angular2/typescript? Want to use paths relative to the project root like 'app/components/calendar', but currently stuck using something like this:

//app/views/order/order-view.ts
import {Calendar} from '../../components/calendar 

Where a Calendar is defined as:

//app/components/calendar.ts
export class Calendar {
}

The lower you go in hierarchy, the more cumbersome it gets. Is there a way to make paths relative to the project root?

I'm working in Visual Studio, and it seems like relative imports are the only way for VS to recognize these imports.

Answer №1

Solution

Starting from TypeScript 2.0, you have the ability to define baseUrl in the tsconfig.json file like this:

{
  "compilerOptions": {
    "baseUrl": "src"
}

This allows you to import components in a more convenient way, for example:

import { Button } from 'components/button';

Additional Information

Handling fallback paths

When using the baseUrl option, it's important to note that TypeScript will:

  1. Attempt to resolve paths based on the baseUrl setting
  2. If a module is not found, it will then consider the moduleResolution option

Configuration for SystemJS

For Angular projects utilizing SystemJS, make sure to adjust the configuration in systemjs.config.js to ensure paths are resolved correctly.


For more details and references, check out:

Answer №2

UPDATE

Avoid using this solution and instead embrace the node module resolution algorithm, as it is crucial for the community's stability. Using alternative methods may cause things to fall apart. Consider utilizing aliases or other suggested solutions.

Summarized Response Although there is a way, it is advisable not to proceed. Modify the compilerOption "moduleResolution" to "classic".

Detailed Explanation

If you are using tsconfig.json, chances are that you are facing challenges like transforming statements such as

import someModule = require ("../../../../someModule"
into
import someModule=require("src/path/to/someModule")
. After spending hours troubleshooting, I discovered that tsc might utilize different algorithms for module resolution. For instance, when working with Atom, the generated tsconfig.json had the compilerOption property moduleResolution set to "node", resulting in the utilization of node's less-than-desirable module resolution algorithm. By switching it to "classic," everything fell into place seamlessly.

Answer №3

Essentially, in Angular 6, there's flexibility to begin the import either from the top or the bottom.

My Two Choices

These options come preconfigured with the default settings created by angular CLI.

  1. Starting from the top:
    This method is preferable when closer to the root of the application.

    import { DateService } from "src/app/shared-services/context/date.service";

  2. Commencing from the bottom

    import { DateService } from "../../../../../../../shared-services/context/date.service";

Context:

TypeScript configuration: tsconfig.json

{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es5",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2017",
      "dom"
    ]
  }
}


Angular's stack

ng -v

Angular CLI: 6.0.8
Node: 8.9.0
OS: win32 x64
Angular: 6.0.7
... animations, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.6.8
@angular-devkit/build-angular     0.6.8
@angular-devkit/build-optimizer   0.6.8
@angular-devkit/core              0.6.8

@angular-devkit/schematics        0.6.8
@angular/cli                      6.0.8
@ngtools/webpack                  6.0.8
@schematics/angular               0.6.8
@schematics/update                0.6.8
rxjs                              6.2.1
typescript                        2.7.2
webpack                           4.8.3

Answer №4

One method to simplify file management and bundling is to create export files with shorter paths.

For example, you could have a components.ts folder at the root of your application containing:

export {Calendar} from './components/calendar'
export {*} from './components/map'

Then import them from components:

import {Calendar, Map} from '../../components';

This approach is more suitable for exporting modules for external use rather than structuring a project.

Alternatively, you can avoid using import statements altogether by utilizing internal modules within your files.

In calendar.ts:

module Components {
    export class Calendar {}
}

Now you can easily use it in any of your project files like this:

new Components.Calendar();

Or import it with an alias:

import Calendar = Components.Calendar;
new Calendar();

Answer №5

In summary: now you can effortlessly utilize src as the root directory and everything will function seamlessly.

When using Angular 2.0, executing ng new my-proj generates a file named my-proj/src/tsconfig.app.json. Within this file, there is a line defining baseUrl:

"baseUrl": "./",

As a result, no modifications are necessary to your configuration, allowing you to organize all imports starting from src. Assuming your project structure resembles:

my-proj/
  README.md
  src/
    app/
      sidebar/
        sidebar.component.ts
      user.service.ts

you can import your files like so:

import { Sidebar } from 'app/sidebar/sidebar.component';
import { UserService } from 'app/user.service';

Note: Sublime Text does not recognize src/tsconfig.json, but only reads the primary tsconfig.json at the top level (refer to this issue). If experiencing Cannot find module 'app/...' errors in Sublime, include the following in your main tsconfig.json file:

"baseUrl": "./src",

This adjustment should resolve any import issues encountered within Sublime Text.

Answer №6

If you're working with a new Angular project created using Angular-CLI, there's no need to make any changes to the default configuration. This remains true as of version 6. To use root-relative imports, simply include src/ at the start of your import paths, like so:

import { VideoPlayerComponent } from 'src/app/pages/shared/video-player/video-player.component';

This approach is preferable to another solution suggested by @MarekDulowski, as root-relative imports are easily distinguishable and can be globally identified through a search for "src/.

I came across this tip on Stack Overflow:

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Looking to showcase a .tif image in your Angular project?

This code is functioning properly for .png images. getNextImage(imageObj:{imageName:string,cityImageId:number,imgNumber:number}):void{ this.imgNumber= imageObj.imgNumber; this.imagePath=`assets/images/${imageObj.imageName}.png`; this.cityIma ...

Eliminate the need for require statements in TypeScript-generated JavaScript files

I am working on a website project and utilizing TypeScript for development. While using the tsc compiler, I noticed that all my JavaScript code compiles correctly. However, when I include an import statement in my TypeScript files, it gets compiled into J ...

Typescript compiler still processing lib files despite setting 'skipLibCheck' to true

Currently, I am working on a project that involves a monorepo with two workspaces (api and frontEnd). Recently, there was an upgrade from Node V10 to V16, and the migration process is almost complete. While I am able to run it locally, I am facing issues w ...

Does property binding truly function as a one-way binding mechanism?

Recently, I began diving into Angular tutorials and came across an interesting point about Angular property binding. It seems that in this particular case, Angular property binding is a one-way binding, meaning that changes to the property of HeroComponent ...

Issue Error: NG0201: NgControl provider not found within NodeInjector

My creativity has hit a roadblock and I'm looking for some help. I decided to use the Reactive Forms Module in Angular, so I imported it into my app.module.ts as shown below: import { ReactiveFormsModule } from '@angular/forms'; @NgModule({ ...

What is the most effective way to condense these if statements?

I've been working on a project that includes some if statements in the code. I was advised to make it more concise and efficient by doing it all in one line. While my current method is functional, I need to refactor it for approval. Can you assist me ...

Property referencing for change detection is a valuable technique

I'm struggling to update my template when changing a boolean property that is referenced in another array property. I expected the changes to reflect in my template, but they are not showing up. Upon initial load, everything appears in its initial st ...

Issue with pre-selected default value in AngularJS TypeScript Kendo UI DropDownList

I have successfully implemented a list of objects for items, but now I am facing a challenge in adding a default selected value. Below is the HTML code for the drop-down: <select kendo-drop-down-list k-options="selectItems" k-ng-mode ...

Angular 2 - resolving the access control allow origin header issue

My project utilizes Spring on the back-end and Angular2 on the front-end. In the webapp folder of my Spring project, there is a JSON file that I am attempting to access from Angular. I can successfully access the file by directly typing "http://localhost: ...

The mat-select function is malfunctioning and failing to select any options

I am facing an issue with a form that includes a mat-select field. Even though I initialize this field with values fetched from the backend using an API call, the mat-select is not able to select any values from the available options. Despite trying variou ...

Tips for extracting year, month, and day from a date type in Typescript

I'm currently working with Angular 7 and I'm facing some challenges when it comes to extracting the year, month, and day from a Date type variable. Additionally, I am utilizing Bootstrap 4 in my project. Can anyone assist me with this? Below is ...

Filter for the final item in Angular

Is there a way to create a filter that specifically retrieves the last element from a list? Alternatively, how can I implement a filter that excludes the last element? Context: I've got a list of items and I need to make sure the last item is editabl ...

How to store angular 2 table information generated using ngFor

I am currently working on a project where I need to create an editable table using data retrieved from the back end. My goal now is to save any updated data. I attempted to use formControl, but it seems to only save the data in the last column. Below is a ...

The matInput directive is experiencing issues when used in a module that is loaded laz

After implementing a lazy loading module, I encountered an issue where elements like matInput were not displaying correctly. Even though the MatInputModule was imported in the module as expected: const routes = [ {path: '', component: AddPlace ...

Is it possible to deactivate the click event on an Angular mat table row?

Within my Angular mat table, I have implemented code that expands a table row when clicked. However, I now need to prevent certain rows from being clickable based on the "element.disable" property. <ng-container matColumnDef="id"> <th mat-hea ...

Is it possible to denote two "any" as the same thing in a TypeScript function signature?

Here is a function to extract items from an array based on a checker function: function extractItemsFromArray(array: any[], isItemToBeRemoved: (item: any) => boolean) { let removedItems = []; let i = array.length; while(i--) if(isItemToBeRemo ...

Is there a way to verify if a value is undefined before including it as an object field?

I'm currently working on an Angular project and I have a query regarding TypeScript. It's about correctly handling the scenario where a field should not be included in an object if its value is undefined. In my code, I am initializing an object ...

The user interface is not being refreshed in the select box after removing control from the reactive form

Within my project, I am utilizing "@angular/cli": "1.2.6", "@angular/core": "^4.0.0" Objective My goal is to create a dynamic form for a product that includes feature inputs. When the user clicks the "add feature" button, a new feature column with a sel ...

Encountering difficulties while trying to integrate a material view in Angular 6, facing the following error

After creating a page using angular 6, I attempted to implement material view for the UI. However, during the implementation process, I encountered the following error: Despite trying to add the material.js lib, I was unable to resolve the issue. An er ...

Is subtyping causing issues in TypeScript's inheritance model?

I am currently utilizing TypeScript for my coding projects, and I have observed that it can allow the production of non-type-safe code. Despite implementing all the "strict" options available to me, the behavior I am experiencing goes against the principle ...