Search code examples
typescripttypescript3.0

TypeScript path mapping "Cannot find module a-mapped/a"


I have a project with the following structure:

┌ tsconfig.json
│ {
│   "compilerOptions": {
│     "baseUrl": ".",
│     "paths": { "a-mapped/*": ["a/*"] }
│   }
│ }
│
├ a
│ └─ a.ts
│    export const a = 1;
└ b
  └─ b.ts
     import { a } from "a-mapped/a";
     export const b = a + 1;

When I run tsc, the resulting b.js contains:

var a_1 = require("a-mapped/a");
exports.b = a_1.a + 1;

If I try to run it with node, I get the error "Cannot find module a-mapped/a".

I expected tsc to generate an import from ../a/a, not a-mapped/a. What am I missing or doing wrong?


Solution

  • I had this problem myself not too long ago. Interestingly enough, typescript will understand path mappings, but keep them as-is in the compiled javascript by design.

    The compiler does not rewrite module names. module names are considered resource identifiers, and are mapped to the output as they appear in the source

    The module names you write are not going to change in the output. the "paths" and "baseURL" are there to tell the compiler where they are going to be at runtime. https://github.com/Microsoft/TypeScript/issues/9910#issuecomment-234729007

    There are several ways to deal with this.

    ts-node

    You can use ts-node instead of node to run your project.

    Pros:

    • easy to use, no-hassle.

    Cons:

    • you might not be able to do this, for example if you're writing browser code, a library, or don't control the runtime environment.
    • Performance might be an issue, especially startup times.

    transformers

    Alternatively you can use typescript transformers to make the compiler output correct javascript files (for example @zerollup/ts-transform-paths and ttypescript).

    Pros:

    • Faster compilation times, you can use ttsc --watch reliably.

    Note: I have tested this setup and its much faster than using any tools when using --watch.

    Cons:

    • At least for now, you need to use a typescript wrapper like ttypescript.
    • Somewhat harder to set-up.

    tools

    Finally, you can use a tool that would fix the paths for you in your generated javascript (ts-module-alias, module-alias, ef-tspm).

    Pros:

    • use unadulterated typescript.
    • Easy to set-up (just run the tool after compiling!)

    Cons:

    • might lead to slower compile times.
    • watch operation is harder to set-up.

    I ended up using ef-tspm to fix the files, and it generally works, although I'm not fully satisfied with the build times, and it's probably worth exploring transformers and ttypescript. In case it helps, I have created a typescript / node project with path aliases set-up.