Reputation: 31983
We have a codebase setup like so:
-A
--utils
---index.ts
--index.ts
--tsconfig.json
-B
--utils
---index.ts
--index.ts
--tsconfig.json
-tsconfig.json
Our root tsconfig.json
contains the following:
"paths": {
"A/*": ["A/*"],
"B/*": ["B/*"],
},
Each package's tsconfig.json
contains the following:
"paths": {
"utils/*": ["./utils/*"],
},
This works for our current purposes, since we currently only use TS for type checking but we actually generate builds with Babel, which has a similar setup in the alias
property of the various .babelrc
files.
We are looking to start running code using ts-node
(or an equivalent) and have run into the issue that at runtime, TS has no idea how to resolve modules. For example:
// A/index.ts
import { someUtil } from 'utils'
export const someFunc() => someUtil();
// B/index.ts
import { someFunc } from 'A';
When we run npx ts-node ./B/index.ts
we get an error saying `Cannot find modules 'utils'.
We know that we can get this working by hoisting everything to the root tsconfig.json
, but it seems superfluous to have to import { someUtil } from 'A/utils
when you are already in package A.
Is there a way to use paths in the manner that we have? We have also read a bit about project references and tried that but it didn't seem to get us anywhere.
Upvotes: 21
Views: 12324
Reputation: 3389
You can use bun, bun supports this out of the box. Run with bun run A/index.ts
will import the utils correctly.
None of the other tools, react-native, webpack, vite, etc, support this.
Upvotes: 0
Reputation: 3331
I hope it's not rude or unhelpful to suggest what you're trying to do might make no sense.
From the point of view of package A, './utils' can be different from the './utils' that package B sees - since they have a different filesystem 'root'. However, the attempt to alias two different './utils' paths as 'utils' from the point of view of BOTH packages creates an inevitable collision.
I am far from sure there's any value in doing this either. I would personally drop the aliasing of folders "./utils" to top-level aliases "utils" and then I think your issues will go away. Probably what you want on a per-package basis is specific includes
, and for the 'local' utils for each package to be addressed relatively to the package...
{
"extends": "../tsconfig.json",
"include": ["index.ts", "utils/index.ts"]
}
Upvotes: 1
Reputation: 1561
Inside the tsconfig.json
file in each of the projects you should use extends
on the root tsconfig
like this:
// A/tsconfig.json
{
"extends": "../tsconfig.json",
...
}
Thay way all the subprojects will inherit the paths from other general packages.
I think you can even define the utils
path on the root, that way you won't have to repeat that either.
More about the extends
option here:
https://www.typescriptlang.org/docs/handbook/tsconfig-json.html#tsconfig-bases
UPDATE
Also you need to use this lib:
https://www.npmjs.com/package/tsconfig-paths
and inside the package.json
in the ts-node
script in the scripts
property you use: ts-node ... -r tsconfig-paths/register ... index.ts
.
This lib will read the packages in ts-config.json
and place them in node_modules
, so your other packages can find them when you run with node or ts-node.
Upvotes: 14