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
- Compile your TypeScript with
@babel/typescript
instead. Drawback: No.d.ts
definition files, and no type safety at compile time. - In a TypeScript parent project, set up your parent (importing) project to resolve imports relative to
node_modules/myModule/lib
usingtsconfig-paths/register
, or manually “absolute to project-root relative” mappings in your parent’stsconfig.json
. Very manual. - Build your library with
rollup-plugin-typescript2
, which produces a single file with no imports, but no typing definition files. - Build using webpack and
awesome-typescript-loader
, with the right plugin configuration. - And other tsc hacks involving symlinks or post-build scripts
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!
✨✨✨
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)