Skip to Content
Course content

92: Path Mapping and baseUrl

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Why am I dealing with "relative path hell"?

You've probably seen it by now. You're working in a file deep inside src/features/billing/components/InvoiceList/InvoiceItem.ts and you need to import a utility from src/core/utils/dateFormatter.ts. Your import ends up looking like this:

import { formatDate } from '../../../../core/utils/dateFormatter';

It's ugly, it's fragile, and if you move that file one folder deeper, the whole thing breaks. I used to just tolerate this until I realized that TypeScript has a way to let us define "absolute" paths from a specific root, making our imports look clean regardless of where the file lives in the directory tree.

How do I actually configure these aliases in my tsconfig?

To fix this, we use two settings in the tsconfig.json: baseUrl and paths. Think of baseUrl as the starting point for all non-relative imports, and paths as a map of shortcuts (aliases).

Let's say we want to use @core/* to refer to anything inside src/core. Here is how you'd set that up:

{
  "compilerOptions": {
    "baseUrl": ".", 
    "paths": {
      "@core/*": ["src/core/*"],
      "@features/*": ["src/features/*"]
    }
  }
}

Now, instead of counting dots and slashes, you can just write:

import { formatDate } from '@core/utils/dateFormatter';

I personally prefer the @ prefix for aliases. It makes it immediately obvious to anyone reading the code that this is a mapped path and not a package installed from npm. It just keeps things tidy.

Why does my code compile but fail when I actually run it?

This is the "gotcha" that trips up almost everyone the first time they use path mapping. Here is the deal: TypeScript does not rewrite your import paths during compilation.

When tsc runs, it checks that @core/utils/dateFormatter exists and is type-safe, but it leaves that string exactly as it is in the resulting JavaScript. When Node.js tries to run that code, it looks for a folder named @core in node_modules, doesn't find it, and crashes with a MODULE_NOT_FOUND error.

To fix this, you need a runtime helper. If you're using Node, the tsconfig-paths package is the standard solution. You just register it at the start of your app:

import 'tsconfig-paths/register';
// Now your @core imports will actually resolve at runtime
import { formatDate } from '@core/utils/dateFormatter';

If you're using a bundler like Webpack or Vite, you'll usually handle this in the bundler's own alias configuration, but the principle is the same: TypeScript handles the type checking, and the runtime/bundler handles the actual resolution.




📋 Practical Task

Refactoring the Invoice Management Import Maze

You have a project with the following structure:

  • src/core/api/httpClient.ts
  • src/core/types/index.ts
  • src/features/invoices/components/InvoiceTable.ts

In InvoiceTable.ts, you currently have these messy imports:

import { HttpClient } from '../../../core/api/httpClient';
import { InvoiceType } from '../../../core/types';

Your Task:

  1. Modify the tsconfig.json to set the baseUrl to the project root and create a path mapping so that any import starting with @core/ points to the src/core/ directory.
  2. Rewrite the imports in InvoiceTable.ts to use the new alias.
  3. Explain in a comment which package you would need to install to ensure these aliases work when running the code via node.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.