Configuring Module Resolution On Typescript and Jest

Gokul Chandrasekaran
4 min readFeb 19, 2019

--

At some point we have all come across insanely long import statements like import { stuff } from ‘../../../../../../../some/deep/component’ in our projects. If you’re just like me and looking for a way to get around this, then you are at the right place. The primary objective of this guide is to explain handling Module Aliases on Typescript and Jest.

TL;DR — Here is a boilerplate project that reflects what is explained

Lets gradually build up our configuration, understanding and resolving issues as they surface.

Important: You can clone this Github project as you walk through the guide.

Step 1: Setting up a basic service.
Within the project folder run git checkout step-1. We have a simple web server with the following directory structure.

.
+-- src
| +-- lib
| | +-- database
| | | +-- index.ts
| +-- repositories
| | +-- person
| | | +-- index.ts
| +-- services
| | +-- person
| | | +-- index.ts
| +-- index.ts
+-- test
| +-- lib
| | +-- database
| | | +-- index.spec.ts
| +-- repositories
| | +-- person
| | | +-- index.spec.ts
| +-- services
| | +-- person
| | | +-- index.spec.ts

Importing the repository module requires the service to traverse up their directory and into the the repositories directory leading the following:
import * from ../../repositories/person . This becomes quite verbose as your project grows in size.

Step 2: Configuring path resolution on tsconfig.js
Run git checkout step-2. Setting the baseUrl and paths specifies to the Typescript transpiler how to resolve modules.
baseUrl: Specifies where to find modules for all imports, all non-relative imports are considered to be relative this.
paths: Configures how to resolve specific names, relative to the baseUrl.

Step 3: Configuring the NodeJS runtime to handle module resolution
Within the project folder run git checkout step-3. Everything runs well on using ts-node and when you compile it using tsc .
However trying to run the transpiled code fails throwing an error like.

Error: Cannot find module '@/services/person'
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:580:15)
at Function.Module._load (internal/modules/cjs/loader.js:506:25)
...

The NodeJS runtime does not know how to resolve our aliases. This is because the tsconfig is only applicable to the Typescript compiler and is not picked up Nodejs runtime. More on this is detailed in this issue on the Typescript repository.

It would be great if the compiler also handled rewriting the generated files.
Unfortunately it doesn’t and we need to specify to the NodeJS runtime how to resolve modules.

We can use a npm module called module-alias to do just that. It has other great features that allow you to define aliases on the fly.
Add the following to the beginning of the src/index.ts to register the module.

require('module-alias/register')

We append a _moduleAliases to our package.json.

Running the newly transpiled code from the dist folder, runs now without any issues.

Step 4: Configuring the Jest runtime to resolve modules.
Within the project folder run git checkout step-4. If you tried running the tests any time until now, it probably failed to run and threw an error:

Cannot find module '@/repositories/person' from 'index.spec.ts'> 1 | import * as personRepository from '@/repositories/person'
| ^
2 | import { findById, getAllPersons } from '@/services/person'
3 |
4 | describe('findById', () => {

By now I am pretty sure, you definitely get the idea. Jest needs a way to figure out how to resolve the modules. We use the moduleNameMapper property to specify module resolution using regular expressions and how to resolve matching paths.

Running npm test should go ahead without any issues any compilation issues.

To be able to use aliases for module paths requires that we configure the

  • Typescript compiler
  • NodeJS runtime
  • Jest runtime

This might seem like lot of work, but the not having to get lost in deep nested import statements is definitely worth it. Provided that it is done just once.

Text editors or IDEs that come with IntelliSense that handle the module imports for us. But given the nature of Javascript this sometimes is a hit and a miss.

Hope you enjoyed reading this as much as I enjoyed writing it.
If you think this will be of help to someone? Please do share. If you liked it, tap the clap below so other people will see this here on Medium. Don’t forget to show some love by following the blog!

--

--