TypeScript Duplicate Identifiers when using npm link

Last night I ran into an issue with TypeScript compilation. I’m working on a frontend web project that uses a library we are developing in another repository. Right now, we’re simultaneously working on both repos, so writing a feature from end to end is a bit of a pain, if one has to first commit to the dependency repository, then pull from there to get the latest version for the app itself. Fortunately, there’s a solution for that: npm link / yarn link. This feature allows you to substitute a local version for a dependency, using symbolic links (or NTFS junction points, if you’re Windows-inclined, like myself).

The problem arises when both your main app and your linked dependency have one or more same dependencies. For example, in our case, the shared dependency was react-intl. If the dependency is not linked, everything works as well as things usually work in js-land (🙄), but once the linking happens, things begin to break.

The core of the problem is that at some point, the TypeScript compiler will encounter two different, possibly identical versions of the same dependency declaration, at which point it will give up and produce a whole mess of errors.

The fix is simple enough, and pretty well documented already: at the top level, where you run the compilation, you add a path mapping, like so:

    "baseUrl": "./src",
    "paths": {
      "*": [
        "../node_modules/@types/*",
        "*"
      ]
    }

What this means (as I understand it) is, for every non-cwd-relative module resolution the TypeScript compiler attempts, it will try the paths specified in the array. This means that when encountering the dependency in the dependent module, it will look for it in the parent module’s node_modules/@types directory, and since it finds it there, it will look no further. This coalesces the duplicate dependencies into one instance, and voila, problem solved. Path mappings can be more specific, too, if you need to target a single problematic package. In this case, I wanted this behavior for all deps, so I went with the easiest route.

Leave a Reply

Your email address will not be published. Required fields are marked *