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

Monitor constantly to determine if an element is within the visible portion of the screen

For a thorough understanding of my query, I feel the need to delve deeper. While I am well-versed in solving this issue with vanilla Javascript that is compatible with typescript, my struggle lies in figuring out how to invoke this function throughout th ...

How can you ensure a code snippet in JavaScript runs only a single time?

I have a scenario where I need to dynamically save my .env content from the AWS secrets manager, but I only want to do this once when the server starts. What would be the best approach for this situation? My project is utilizing TypeScript: getSecrets(&qu ...

The TypeScript error arises when an element implicitly contains an 'any' type due to the inability to use an expression of type 'any' to index a specific type

Encountering an Issue: Element implicitly has an 'any' type because expression of type 'any' can't be used to index type '{ foo: string; bar: string; }'.ts(7053) Within the following code snippet: const CATEGORY_COLORS ...

Utilizing Typescript and Jest to prevent type errors in mocked functions

When looking to simulate external modules with Jest, the jest.mock() method can be utilized to automatically mock functions within a module. After this, we have the ability to modify and analyze the mocked functions on our simulated module as needed. As ...

Unable to access specific data from the JSON string retrieved from the backend, as it is returning a value of undefined

After receiving a JSON string from the backend, my frontend is encountering issues when trying to index it post using JSON.parse(). The indexed value keeps returning as undefined, even though it's a JSON object literal and not within an array. For th ...

Encountering an error when using the Vue 3 TypeScript Composition API for style binding with an asynchronous

I utilized nexttick alongside an async method to update a DOM element. However, I am encountering issues with returning the correct style type. An error message pops up stating: error TS2322: Type 'Promise<{ maxHeight: string; }>' is not ...

Preventing specific directories from being imported in a Typescript project

I am intrigued by the idea of restricting files within a specific scope from importing files from another scope. Let's consider this example: Imagine we have the following project structure: project/ ├── node_modules/ ├── test/ ├── ...

Animate in Angular using transform without requiring absolute positioning after the animation is completed

Attempting to incorporate some fancy animations into my project, but running into layout issues when using position: absolute for the animation with transform. export function SlideLeft() { return trigger('slideLeft', [ state('void&a ...

Having trouble capturing emitted events from a child component in Angular 2+?

I have a question as a beginner. I'm trying to send a message from the child component to the parent component but for some reason, it's not working. app.component.html <app-cart-component> [items]="rootItems" (outputItems)=&quo ...

Exploring the functionality of Material components within a nested child component

I am facing an issue with my TestComponent, which uses a <mat-stepper> in its template. Due to the specific context of the stepper, I have to programmatically move to the next step instead of using the matStepperNext directive on a button. Here is a ...

Enhancing data validation and converting strings to dates with Nest.js - DTO approach

Anticipating the upcoming request to adhere to the ISO 8601 standard timestamp format, something similar to "2023-12-04T15:30:00Z" (typically embedded as a string within JSON data that needs conversion to a JavaScript Date object). This is my Data Transfe ...

What is the trick to make the "@" alias function in a Typescript ESM project?

My current challenge involves running a script using ESM: ts-node --esm -r tsconfig-paths/register -T src/server/api/jobs/index.ts Despite my efforts, the script seems unable to handle imports like import '@/server/init.ts': CustomError: Cannot ...

Guide on creating dynamic route paths for includes within a Pug template

Need help creating a dynamic include For example: h1 include path/#{object} or include path/+{object}+{a:true,b:11} Something similar to the above. If anyone knows how to achieve this using Mixins in pug, please provide an example for include. ...

Encountering a problem when trying to use event.target.value in an Angular TypeScript application

Here is the code from my app.component.html : <h1>Password Generator</h1> <div> <label>Length</label> </div> <input (input)="onChangeLength($event.target.value)"/> <div> <div> <input ...

What methods does Angular use to determine the parameter types of a constructor?

I've been experimenting with replicating Angular's approach to interpreting the constructor in an injectable service. function Injectable() { return function<T extends { new (...args: any[]): {} }>(con: T) { return class extends con ...

The refresh function in the table is not working as expected when implemented in a functional component. The table being used is Material

I am currently utilizing MaterialTable from https://material-table.com/#/docs/features/editable to manage data and perform CRUD operations within my application. I am seeking a way to automatically refresh the table data after any CRUD operation (add, upda ...

What are the best practices for utilizing an array of routes?

I'm new to working with react but I noticed something strange. My routes are currently set up like this: <Main> <Route exact path="/home" component={Home} /> <Route exact path="/home1" com ...

Utilizing TypeScript for enhanced Chrome notifications

I am currently developing a Chrome app using TypeScript (Angular2) and I want to implement push notifications. Here is the code snippet for my notification service: import {Injectable} from 'angular2/core'; @Injectable() export class Notificati ...

Error in TypeScript: The object may be null when using the window.open method

Is there a way to implement this code in Typescript? window.open(externalUrl, '_blank').focus(); Encountering the following TypeScript error: Object is possibly 'null'.ts(2531) I attempted the following solution without success: ...

Troubleshooting issues with sorting and pagination in Angular Material table functionality

I am experiencing an issue with sorting and pagination using an Angular material table. The data is being fetched from a store as an observable and successfully displayed in the table. Even though the column names for sorting match the column definitions, ...