I am currently working on an Electron app using TypeScript and Angular2, for which I have created many different classes, all in separate files. In order to make the refactoring of my app easier, I would like to not have to use the relative path when importing those classes.
Right now, to import them, I use this syntax: import {Trigger} from './../../trigger/ts/trigger.component';
What I would like to do is use a syntax that looks like this: import {Trigger} from 'trigger.component';
Is that possible?

- 433
- 1
- 4
- 16
-
2This has been asked a lot. Hopefully someone replies soon. http://stackoverflow.com/questions/35065880/typescript-declare-module – Langley Jan 28 '16 at 18:10
-
2Possible duplicate of [How to avoid imports with very long relative paths in Angular 2?](http://stackoverflow.com/questions/34925992/how-to-avoid-imports-with-very-long-relative-paths-in-angular-2) – David Sherret Jan 28 '16 at 20:40
-
Good question. Now that typescript consolidates modules into a single module this is likely to be a common problem. I'd like typescript to be aware of the AMD configuration but I don't think it is yet. I bet you can do this with module definitions that import then export the class but that's a high maintenance pain until definition flattening comes around. – Corey Alix Jan 28 '16 at 21:08
-
Hot off the press, looks like baseUrl paths might allow this. https://github.com/Microsoft/TypeScript/issues/5039 – Corey Alix Jan 28 '16 at 21:25
-
I know it is 6 years later, but I've reviewed this and other q/a around NOT using relative paths in TS project (don't have an issue in JS project) for some months now and can't get it working for the life of me. There's a lot of "you can try this", but no 100% answer. Did anything work for you??? – Neil Gaetano Lindberg Apr 13 '22 at 13:01
5 Answers
Better to use below configuration in tsconfig.json
{
"compilerOptions": {
"...": "reduced for brevity",
"baseUrl": "src",
"paths": {
"@app/*": ["app/*"],
"@trigger/*": ["app/trigger/ts/*"]
}
}
}
For your case, use can do either import {Trigger} from '@app/trigger/ts/trigger.component';
or import {Trigger} from '@trigger/trigger.component';
or any level of path you can configure.

- 3,139
- 1
- 25
- 24
You can create one file, for example: components.ts and in that component reference to all components, like:
export {Trigger} from '../trigger/ts/trigger.component'
export {Cmp} from '../cmp/ts/cmp.component'
...
Than, when you want to load one component, you can do:
import {Trigger} from '../components.ts'
It is good practice for grouping things.

- 6,369
- 2
- 20
- 31
-
I tried doing that, but I sometimes get errors like `EXCEPTION: Cannot resolve all parameters for TriggerComponent` when including a service. But this service may be included without error in another component... I have to admit I am quite confused... – Yann Lelong Jan 28 '16 at 23:27
-
Interesting, i did not face that problem. This aggregation of files into one is common thing in Angular2: http, core, common files... – Vlado Tesanovic Jan 29 '16 at 07:11
-
Really good advice. My path to some file was wrong and I didn't know why. I just put it into another component and now it works, cause I know the path to the component – IonicMan Nov 05 '20 at 11:22
I created an exporter using ScriptCS to do just that. I wrote it in C#, but you're welcome to re-write it in whatever language you prefer.
It allows you to have an export file in the root of each component directory which you can import by doing:
import {LoginPage, HomePage} from '../pages/export'
or
import {NavBarComponent, HeroCardComponent} from '../controls/export'
Say you have multiple components in a specific directory such as:
- app/pages/login-page/login-page.ts
- app/pages/home-page/home-page.ts
- app/controls/nav-bar.ts
- app/controls/hero-card.ts
if you run scriptcs exporter.cs -- app/pages app/controls
It will generate an output file called export.ts
in each of the specified directories with an export statement for each of the classes contained in the directories (which are iterated through recursively)
exporter.cs
// USAGE
// scriptcs exporter.cs -- app/Templates app/Controls
using System.Text.RegularExpressions;
CreateExports();
public void CreateExports() {
// e.g. 'C:\Apps\MyProject'
string rootDir = new DirectoryInfo(@".\").FullName;
string exportFileName = "export.ts";
List<string> exportDirectoryPaths = new List<string>();
foreach (string argument in Env.ScriptArgs) {
if (argument.Contains(".ts"))
exportFileName = argument;
else
exportDirectoryPaths.Add(argument);
}
Console.WriteLine("File Name:" + exportFileName);
foreach (string exportDirPath in exportDirectoryPaths) {
// e.g. 'app\Templates'
var exportDirPathFixed = exportDirPath.Replace("/", "\\");
Console.WriteLine(String.Format("Exporting -> {0}", exportDirPath));
List<ExportEntry> exportEntriesToWrite = new List<ExportEntry>();
// e.g. 'C:\Apps\MyProject\app\Templates'
DirectoryInfo exportDir = new DirectoryInfo(rootDir + exportDirPathFixed);
foreach (FileInfo file in exportDir.EnumerateFiles("*.ts", SearchOption.AllDirectories)) {
// Don't export the export file ;)
if (file.Name == exportFileName)
continue;
// e.g. toAdd = {
// RelativepathToExportDirectory = './app/templates/template-one.component'
// ClassName = 'TemplateOneComponent' (Parsed from file contents, works with interfaces)
ExportEntry toAdd = CreateExportEntry(file, exportDirPathFixed, rootDir);
exportEntriesToWrite.Add(toAdd);
}
CreateExportFile(exportDir.FullName + "\\" + exportFileName, exportEntriesToWrite);
}
}
private void CreateExportFile(string exportFilePath, IEnumerable<ExportEntry> exportEntries) {
string textToWrite = "";
foreach (ExportEntry entry in exportEntries) {
textToWrite += entry.ToString() + Environment.NewLine;
}
Console.WriteLine("Text: " + Environment.NewLine + textToWrite);
File.WriteAllText(exportFilePath, textToWrite);
}
// -- Create Export Entry -- //
private ExportEntry CreateExportEntry(FileInfo exportFile, string exportDirPath, string rootDir) {
ExportEntry toReturn = new ExportEntry() {
ClassName = GetFirstExportClassName(exportFile),
RelativepathToExportDirectory = exportFile.FullName.Remove(0, rootDir.Length + exportDirPath.Length).Replace(".ts", ""),
};
return toReturn;
}
private string GetFirstExportClassName(FileInfo exportFile) {
string className = null;
Regex regular = new Regex(@"(?<=export[\s+]class|interface)[^s+][^\s]+");
using (StreamReader streamer = new StreamReader(exportFile.OpenRead())) {
string contents = streamer.ReadToEnd();
Match componentNameMatch = regular.Match(contents);
className = componentNameMatch.ToString().Replace("{", "");
}
return className;
}
public class ExportEntry {
public string RelativepathToExportDirectory { get; set; }
private string _ClassName;
public string ClassName {
get { return _ClassName; }
set { _ClassName = value.Trim(); }
}
/// <summary>
/// Returns the formatted export entry
/// e.g. " export {MyComponents} from './Components/my-component.component' "
/// </summary>
/// <returns></returns>
public override string ToString() {
// export { AppComponent} from './my-template/my-template.component'
return String.Format("export {{ {0} }} from '.{1}';", this.ClassName, this.RelativepathToExportDirectory).Replace('\\', '/');
}
}

- 13,631
- 4
- 38
- 44
A simple way of achieving this is by using the paths of Typescript v2.*, like it is used here: https://github.com/MarkPieszak/aspnetcore-angular2-universal
In summary, you can add a index.ts file to a folder, like
export * from './app.component'
export * from './shared/other.component'
and then have webpack to take care of it. You should add to your webpack.config.js
const clone = require('js.clone');
const ContextReplacementPlugin = require('webpack/lib/ContextReplacementPlugin');
const TsConfigPathsPlugin = require('awesome-typescript-loader').TsConfigPathsPlugin;
[...]
const config = setTypeScriptAlias(require('./tsconfig.json'), {
[...]
plugins: [
new ContextReplacementPlugin(
// The (\\|\/) piece accounts for path separators in *nix and Windows
/angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/,
root('./ClientApp')
),
new TsConfigPathsPlugin({
tsconfig: 'tsconfig.json'
}), [...]
with these help functions:
function setTypeScriptAlias(tsConfig, config) {
var newConfig = clone(config);
newConfig = newConfig || {};
newConfig.resolve = newConfig.resolve || {};
newConfig.resolve.alias = newConfig.resolve.alias || {};
var tsPaths = tsConfig.compilerOptions.paths;
for (var prop in tsPaths) {
newConfig.resolve.alias[prop] = root(tsPaths[prop][0]);
}
return newConfig;
}
function root(args) {
args = Array.prototype.slice.call(arguments, 0);
return path.join.apply(path, [__dirname].concat(args));
}
And finally define the paths in your tsconfig.js
"compilerOptions": {
[...]
"paths": {
"app": [ "./ClientApp/app" ]
},[...]
Then you can just import by the "app" path like
import { AppModule } from 'app';

- 89
- 1
- 1
- 6
I was able to get it to work by adding the following to tsconfig.app.json
:
"compilerOptions": {
"baseUrl": "./",
...
}
as described in https://www.typescriptlang.org/v2/en/tsconfig#moduleResolution. It was already in tsconfig.json
, but apparently that is only used for IDE integration.

- 1,449
- 1
- 15
- 13