Typescript: resolve relative import path when using symlinks
Asked Answered
T

1

11

This seems like a dumb question, but I struggle to find the answer.

The situation

Here is my folder structure:

myProject/
├── module1/
│   ├── config.ts
│   └── init.ts #symlink
├── module2/
│   ├── config.ts
│   └── init.ts #symlink
└── symlinks/
    └── init.ts # the real not duplicated file

The file init.js import local files like so:

import config from './config'

// ...

The problem

The problem is that typescript throws Cannot find module './config' or its corresponding type declarations

I tried playing with typescript option preserveSymlinks but it didn't solve my problem

I know about other ways to achieve my goal but it's overkill for just one file and it doesn't solve relaying on a relative path (like creating a npm module, creating a function and pass relative file content as parameter or even generating files at runtime...)

=> I am working with typescript in a monorepo.

Is it possible to use symlinks this way? If no, are there other (simple) alternatives?

EDIT: I have made this example repo, you can use it as a base for experiments

Trina answered 9/1, 2023 at 15:59 Comment(2)
What is inside init.ts that "forces" you to use something like this?Metacarpal
It's just relative paths to config files and other local files, the real setup is much more complex and with a lot of files imported. For example, there is a start server script, that is triggered via package.json start command. So it's much harder to create a function and pass configs as parameters for example.Trina
S
-4

By default, TypeScript resolves modules based on the physical path of the file, not the resolved path after following any symbolic links. So, in your case, when you try to import config from ./config, TypeScript looks for the file at the physical path myProject/module1/config.ts or myProject/module2/config.ts, but it's actually located at myProject/symlinks/config.ts.

You can tell TypeScript to resolve modules based on the resolved path by setting the resolveSymlinks option to true in your tsconfig.json file:

{
  "compilerOptions": {
    // ...
    "resolveSymlinks": true
  },
  // ...
}

This will cause TypeScript to follow symbolic links when resolving modules, so it should be able to find your config file. Note that you may also need to set preserveSymlinks to true if you're using tools like Webpack that may alter the resolved path.

Another option is to use module aliases in your tsconfig.json file to map the ./config path to the correct location. For example:

{
  "compilerOptions": {
    // ...
    "baseUrl": ".",
    "paths": {
      "*": ["*", "symlinks/*"]
    }
  },
  // ...
}

This will tell TypeScript to look for all modules in the symlinks directory, as well as in their original locations. Then, you can import config like this:

import config from 'module1/config';

This should work regardless of whether init.ts is a symlink or a regular file.

Sudhir answered 24/3, 2023 at 0:53 Comment(4)
Hi, I have already used preserveSymlinks options but it was of no use. The problem here are the paths imported inside the simlinked files that are relative to the original file and not the symlink file. Have you tried to run a similar project ?Trina
I have updated my answer, you can now find a github link with a reproductible exampleTrina
resolveSymlinks does not exist in the compilerOptions.Majordomo
This answer is very similar to AI generated. If only because resolveSymlinks is not present (and has never been present) in tsconfigProtoplast

© 2022 - 2024 — McMap. All rights reserved.