Fixing Absolute Imports in Typescript

4th Oct 2018

TypeScript has a cute feature with a small problem causing a huge impact.

Cute Feature: absolute imports with baseUrl

{
  "compilerOptions": {
    "baseUrl": "src"
  }
}

Now you can import all files relative to baseUrl, instead of to the file you’re in! In larger projects this saves you a lot of import from '../../views' annoyance — you can write import from 'views' instead, anywhere in your project.

Unfortunately, these imports won’t work in Javascript any more. And the TypeScript team are opposed to the compiler converting these import paths to relative when it does compile to Javascript, since:

Module names are considered resource identifiers and are not changed by the compiler.

So now your module can’t be imported into other modules

Most build toolchains will have some support but with tradeoffs. So, there are some… workarounds

Best solution: Use the compiler itself to compile these imports to Javascript

The TypeScript compiler supports an API much like Babel’s, which allows us to transform the code it outputs. Transformers can basically turn any code into any other valid code, so we use it to re-write easy-to-write but hard-to-compile absolute imports into relative imports which node and Javascript expect. ttypescript makes it easy to compile or run with transformer plugins!

✨✨✨

grrowl/ts-transformer-imports

Transforms your TypeScript absolute imports to be relative

✨✨✨

It’s as easy as adding the plugin to your tsconfig.json and running ttsc or tts-node as you’d usually run their native typescript equivalents.

We’ve been using it at ActivePipe in production and are enjoying the advantage of absolute import paths when refactoring and breaking apart our larger modules while still maintaining flexibility of compiling to basically any project.

Contributions and bug reports welcome and hopefully this eases some pain the TypeScript community has been having writing modular and packaged code.

(this post originally appeared on Medium)