When importing modules (e.g. classes, interfaces, etc) in TypeScript, the most common method is to allow the IDE to create a relative import statement. Here is an example:

import { ClassB } from '../../../../other/domain/ClassB';

However, there is an easy way to completely avoid these long import statements. All it requires is some simple and minor modifications to your tsconfig.json file.

Let’s assume we have the following silly example of a deeply nested directory structure.

src/
    deeply/
        nested/
            directory/
                components/
                    ClassA.ts
    other/
        domain/
            ClassB.ts
package.json
tsconfig.json
etc...

Let’s also assume that ClassA.ts and ClassB.ts have the following contents:

import { ClassB } from '../../../../other/domain/ClassB';


export class ClassA {
    private _classB: ClassB;

    public constructor() {
        this._classB = new ClassB();
    }
}
import { ClassA } from '../../deeply/nested/directory/components/ClassA';


export class ClassB {
    private _classA: ClassA;

    public constructor() {
        this._classA = new ClassA();
    }
}

The import statements in both of those classes are relative. Of course, if the path of either of the classes change, then all relative import references would need to change as well. Fortunately, TypeScript allows to easily and quickly define module paths within our tsconfig.json file. For this example, you would add the following lines to your tsconfig.json file:

{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "@components/*": [ "deeply/nested/directory/components/*" ],
      "@domain/*":     [ "other/domain/*" ]
    }
  }
}

Now, all we have to do is modify the import statements in ClassA.ts and ClassB.ts like so:

// import { ClassB } from '../../../../other/domain/ClassB';
import { ClassB } from '@domain/ClassB';


export class ClassA {
    private _classB: ClassB;

    public constructor() {
        this._classB = new ClassB();
    }
}
// import { ClassA } from '../../deeply/nested/directory/components/ClassA';
import { ClassA } from '@components/ClassA';


export class ClassB {
    private _classA: ClassA;

    public constructor() {
        this._classA = new ClassA();
    }
}

This has the additional benefit of eliminating the need to update all of the relative paths in every relevant file when any of them change. Instead, we can update them in a single location, namely tsconfig.json. The amazing TypeScript team at Microsoft has provided additional documentation of this feature here. Lastly, I am including an example Github repo containing a project with all of the code.

UPDATE: Your webpack config will need some adjustment to resolve the non-relative references. The resolve.alias setting is useful for this. Also, this will not easily work in Node.js. One look at the emitted code and you will understand why.

// tsc emitted code
var ClassB_1 = require("@domain/ClassB");