DEV Community

Mayowa Ojo
Mayowa Ojo

Posted on

Avoid deeply nested imports with path mapping in typescript

image from unsplash

Photo by Lukas Beran on Unsplash

Importing modules with relative paths can be such a pain as your codebase grows and you start splitting large files into smaller reusable modules. Files get nested very deep so much you stare at your folder structure perplexed. Consider the following folder structure:

root/
   tsconfig.json
   types.d.ts
   .env
   src/
      server.ts
      database/
      models/
      routes/
         posts/
         comments/
      controllers/
         posts/
         comments/
         media/
      utils/
         database/
            seed.ts
         workers/
            publisher.ts

Say you want to import a function from a module in src/utils/workers into the post controller, it's already looking like a mess: import { function } from "../../utils/workers/publisher.ts". This can get even messier when file locations change and you need to update everywhere you imported that file.

One way to tackle this is to use typescript path mapping. You define a namespace in your tsconfig mapping it to a specified path by declaring a paths field in your tsconfig.json under compilerOptions like so:

{
   "compilerOptions": {
      "baseUrl": ".",
      "paths": {
         "@workers/*": ["src/utils/workers/*"],
         "@mediaControllers/*": ["src/controllers/media/*"]
      }
   }
}

Here, we set the baseUrl to the root directory, which is necessary for creating path maps. We create a namespace "@workers" which maps to the path "src/utils/workers/". The '@' symbol is not necessary, it's just there to easily standout and make it recognizable as a namespace.

Now if we want to import a module from workers, we simply use the namespace. i.e import { function } from "@workers/publisher.ts". We don't have to worry about relative paths anymore, and when we move files from their original location, we just simply update the path map. So problem solved! 😁️.

Note that typescript resolves paths relative to baseUrl so keep that in mind when creating path maps.

Top comments (7)

Collapse
 
thekashey profile image
Anton Korzunov

The main question is about the naming convention:

  • workers? Well sounds like a npm package name. How to distinguish?
  • @workers? Well, actually the same - like a package from an org.
  • self/workers or @self/workers? Scoped but verbose.

There is also one more case - use eslint/tslint to group imports and thus separate something from node_modules from your own stuff.

But in any case - this is a must-have feature.

Collapse
 
unorthodev profile image
Mayowa Ojo

The names you choose depends on the way your project is structured. You can also decide to entirely avoid such names that can cause conflicts. It's entirely up to you and that's why the "@" symbol can help distinguish.

Collapse
 
ca0v profile image
Corey Alix

Seems like node "imports" dictate the prefix to be "#".

Collapse
 
unorthodev profile image
Mayowa Ojo

I only just discovered it recently and it's made my life so much easier, not to mention my code looks cleaner too.

Collapse
 
joshuaamaju profile image
Joshua Amaju

VS code automatically updates import paths when you move files...

Collapse
 
buinauskas profile image
Evaldas Buinauskas

Doesn't make code more readable 🙂

Collapse
 
ca0v profile image
Corey Alix

Typescript does not substitute the correct path so how are you resolving "@workers"?