Tips for having tsc Resolve Absolute Paths in Module Imports with baseUrl Setting

In a typescript project, imagine the following organizational structure:

|   package.json
|   tsconfig.json
|               
\---src
    |   app.ts
    |   
    \---foobar
            Foo.ts
            Bar.ts

The tsconfig.json file is set up to have ./src/ as the baseUrl.

{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es6",
        "noImplicitAny": true,
        "removeComments": true,
        "preserveConstEnums": true,
        "outDir": "./dist/",
        "baseUrl": "./src/"
    },
    "include": [
        "./src/**/*"
    ],
    "exclude": [
        "node_modules"
    ]
}

If we wish to import Foo into Bar.ts, setting the baseUrl allows us to use absolute paths for importing modules.

import { Foo } from 'foobar/Foo'

Instead of using relative paths like this:

import { Foo } from './Foo'

Based on my understanding, the TypeScript compiler should be able to resolve foobar/Foo to ./Foo automatically during compilation of Bar.ts.

import { Foo } from 'foobar/Foo';

export class Bar {
  foo: Foo;

  constructor(num: number) {
    this.foo = new Foo(num);
  }
}

Although running tsc compiles without errors, inspecting the compiled Bar.js reveals that the path resolution has not been done accurately, resulting in a Cannot find module error if executed.

"use strict";
const Foo_1 = require("foobar/Foo");
class Bar {
    constructor(num) {
        this.foo = new Foo_1.Foo(num);
    }
}
exports.Bar = Bar;

Hence, the question arises: How can I ensure that tsc accurately resolves absolute paths when importing modules with baseUrl? And if this functionality is unattainable, what is the purpose of baseUrl exactly?

Answer №1

The solution was provided by @DenisPshenov in a buried comment within a thread. I will share it here...

In order for Node to resolve absolute paths, it is necessary to specify the base URL using the NODE_PATH environment variable:

For Linux / macOS:

NODE_PATH=dist/ node ./dist/index.js

For Windows Powershell:

$env:NODE_PATH="dist/"
node ./dist/index.js

Answer №2

If you're finding it difficult to solve this particular issue, here's a solution that might help.

npm install -D tsc-alias
# Add the following to your package.json under scripts:
tsc && tsc-alias

Answer №3

Your module loader is unable to locate the module with the absolute path foobar/Foo, which is causing the issue.

The TypeScript compiler (tsc) is correctly resolving the module paths, as no compilation errors are occurring. However, it relies on you to properly configure your module loader.

For instance, the RequireJS documentation explains:

Supported configuration options:

baseUrl: the root path to use for all module lookups.

The TypeScript documentation elaborates on the need for baseUrl:

Using a baseUrl is a common practice in applications utilizing AMD module loaders where modules are “deployed” to a single folder at runtime. These modules may exist in different directories, but a build script consolidates them.

Answer №4

tsc is having trouble converting paths to relative paths, even though you have configured baseUrl and paths. Keep in mind that paths is primarily for helping with linting your code while coding in the editor. To make it work properly, consider using ts-node along with the tsconfig-paths module:

$ yarn add ts-node tsconfig-paths --dev

After installing those packages, run this script:

"start": "ts-node -r tsconfig-paths/register app.ts"

This should ensure that everything runs smoothly.

Answer №5

Ouyang Chao's solution is accurate, but it may not work during tests. To make it functional, you need to update your tsconfig.json with the following settings:

"compilerOptions": {
  "target": "ES2022",
  "module": "commonjs",
  "esModuleInterop": true,
  "outDir": "./dist",
  "baseUrl": "./",
  "paths": {
    "@controllers/*": ["src/controllers/*"],
    "@fixtures/*": ["src/fixtures/*"],
    "@interfaces/*": ["src/interfaces/*"],
    "@services/*": ["src/services/*"],
    "@views/*": ["src/views/*"]
  }
}

Additionally, update your jest configuration in the package.json file as follows:

"jest": {
  "preset": "ts-jest",
  "testEnvironment": "node",
  "collectCoverage": true,
  "coveragePathIgnorePatterns": [
    "node_modules",
    "dist",
    "tests"
  ],
  "moduleNameMapper": {
    "^@services/(.*)$": "<rootDir>/src/services/$1",
    "^@controllers/(.*)$": "<rootDir>/src/controllers/$1",
    "^@fixtures/(.*)$": "<rootDir>/src/fixtures/$1",
    "^@interfaces/(.*)$": "<rootDir>/src/interfaces/$1",
    "^@views/(.*)$": "<rootDir>/src/views/$1"
  }
},

You can now execute your node.js TypeScript project using the commands below:

"scripts" : {
  "start": "npx tsc && npx tsc-alias && node ./dist/src/index.js",
  "test": "npx tsc && npx tsc-alias && jest"
}

This setup allows you to utilize absolute imports within both your node.js TypeScript application and your jest tests.

import { petView } from '@views/petView'

Lastly, the placeholder value of <rootDir> in the package.json file will automatically adopt the defined baseURL value from your tsconfig.json.

Answer №6

To achieve this, you can utilize the path feature in your tsconfig file:

{
  "compilerOptions": {
    "baseUrl": "src",
    "paths": {
        "app/*": ["app/*"],
        "config/*": ["app/_config/*"],
        "environment/*": ["environments/*"],
        "shared/*": ["app/_shared/*"],
        "helpers/*": ["helpers/*"],
        "tests/*": ["tests/*"]
    },
}

By configuring these custom prefixes in your TypeScript setup, you enable the file resolver to locate code more efficiently. This approach helps avoid lengthy relative paths within your project.

Visit https://www.typescriptlang.org/tsconfig for more information.

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

Angular 5 is unable to access the value of a form control when the name attribute is not specified

Snippet of HTML code: <li class="dropdownfilter" *ngIf="this.arr.inclues('Male')" (click)="getValueGender('Male',1,)" [(ngModel)]="M"><a>Male</a></li> I encountered the following error: ERROR Error: No value a ...

What is the TypeScript syntax for indicating multiple generic types for a variable?

Currently working on transitioning one of my projects from JavaScript to TypeScript, however I've hit a roadblock when it comes to type annotation. I have an interface called Serializer and a class that merges these interfaces as shown below: interfa ...

Experimenting with Cesium using Jasmine (Angular TypeScript)

I have a TypeScript app built using Angular that incorporates Cesium: cesium-container.component.ts import { Component, ElementRef } from '@angular/core'; import { Viewer } from 'cesium'; import { SomeOtherCesiumService } from 'sr ...

Posting an array as form data in Angular Typescript: A step-by-step guide

Hello there, I'm currently developing an application using Angular 8 and integrating web.api within .net core 2.2. One of the challenges I encountered is dealing with multi-selectable checkboxes in a form that also includes "regular" inputs and file ...

Struggling to create a functioning toggle button using jQuery in a React application

I've encountered an issue with my react web application. I'm trying to implement a voting system where clicking the like button changes its color and functionality, allowing it to be liked only once. If clicked again, it should return to a neutra ...

Angular CLI's selection of third-party libraries that are not available on npm repositories

Currently in the process of migrating an app from Angular 2 to Angular CLI Now facing the challenge of importing 3rd party libraries like orbitcontrols.js that are not available on npm or bower. After researching on https://github.com/angular/angular-cli ...

Enhance the performance of your React/NextJS app by controlling the rendering of a component and focusing on updating

I'm facing an issue with my NextJS application that showcases a list of audio tracks using an <AudioTrackEntry> component. This component receives props like the Track Title and a Link to the audio file from an external data source. Within the ...

A guide on how to implement promise return in redux actions for react native applications

I'm using redux to handle location data and I need to retrieve it when necessary. Once the location is saved to the state in redux, I want to return a promise because I require that data for my screen. Here are my actions, reducers, store setup, and ...

What is the best way to individually update elements in an array in Ionic v5?

As a newcomer to Ionic and TypeScript, I would appreciate your kindness in helping me with a problem I am facing. I have an array of objects that get updated when adding an 'exercise', where you can specify the number of sets and reps. The issue ...

Storing user input as an object key in typescript: A comprehensive guide

When delving into Firestore for the first time, I quickly learned that the recommended modeling approach looks something like this: check out the model here members { id: xyz { name: Jones; ...

Revise Swagger UI within toggle button switch

My project aims to showcase three distinct OpenApi definitions within a web application, enabling users to explore different API documentation. The concept involves implementing a toggle button group with three buttons at the top and the Swagger UI display ...

Where is the optimal location for placing a JavaScript listening function within an Angular component?

Summary: Incorporating a BioDigital HumanAPI anatomical model into my Angular 5 application using an iFrame. The initialization of the API object is as follows: this.human = new HumanAPI(iFrameSrc); An important API function human.on(...) registers clic ...

@vx/enhanced responsiveness with TypeScript

I am currently utilizing the @vx/responsive library in an attempt to retrieve the width of a parent component. Below are snippets from my code: import * as React from 'react' import { inject, observer } from 'mobx-react' import { IGlob ...

A guide on creating a function that can detect if an object is not iterable and then throw an error

Exploration Uncomfortable type definition at the library: declare type Extension = { extension: Extension; } | readonly Extension[]; Type-validation function export function isIterable(x: any): x is Iterable<unknown> { return Symbol.iterator ...

Connection to mongo is currently unavailable for Middleware next

This code snippet shows a middleware for Next, which is designed to read the subdomain and check if it exists in the database. import { getValidSubdomain } from '@/lib/getValidSubdomain'; import { NextResponse } from 'next/server' impor ...

Issues arising with utilizing Github for hosting Angular applications

After developing a site with Angular, everything was running smoothly on my local host. However, when I decided to host the site on GitHub, two errors appeared. You can access my site through this link: Here is a screenshot of the errors encountered [1]: ...

In TypeScript, what is the format in which the final type result of a generic utility type is shown?

After utilizing the provided code, I have encountered an issue with retrieving the ultimate type of type A in the editor. Despite my efforts, the editor persistently showcases the composite form of the generic utility, complicating the process of verifyi ...

Tips for accessing a specific value within an array of objects using a key

Is there a way to retrieve the value in an object array based on a key that is present within the same array? The structure of the object array is as follows: const objectArray = [ {key: "1", value: "12321"}, {key: "2", value: "asdfas"} ] For ex ...

Creating multilingual menus with ABP and Nebular

Currently, I am in the process of developing an application using ABP framework version 4.4 and integrating the Nebular theme as opposed to the default basic theme. Amidst various challenges faced during this migration, one particular issue stands out - lo ...

Issue with using useState inside alert: unexpected empty array

I am facing an issue with the 'exercises' useState in my code. The useEffect function correctly prints the 'exercises' after every change, but when I press the 'Finish' button, the 'exercises' suddenly become empty. ...