Exploring project references in TypeScript 3 with distinct `outDir` configurations

I am eager to utilize the project references functionality in TypeScript 3.1. Initially, my project's directory structure post-compilation appears as follows:

.
├── A
│   ├── a.ts
│   ├── dist
│   │   ├── A
│   │   │   └── a.js
│   │   └── Shared
│   │       └── shared.js
│   └── tsconfig.json
└── Shared
    ├── dist
    │   └── shared.js
    ├── shared.ts
    └── tsconfig.json

Inside the Shared directory:

shared.ts:

export const name = "name";

tsconfig.json:

{
  "compilerOptions": {
    "target": "es5",                          
    "module": "commonjs",                     
    "outDir": "dist",                        
    "strict": true
  }
}

Directory contents of A:

a.ts:

import { name } from "../Shared/shared"; 

console.log(name);

tsconfig.json:

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "outDir": "dist",
    "strict": true
  }
}

The issue I encountered was that all files were being duplicated in A's output directory which prompted me to explore project references.

To enable project references, I made adjustments to the Shared/tsconfig.json and A/tsconfig.json.

"composite": true
"references": [
  { "path": "../Shared" }
]

After compilation, the expected directory structure looks like this:

.
├── A
│   ├── a.ts
│   ├── dist
│   │   └── a.js
│   └── tsconfig.json
└── Shared
    ├── dist
    │   ├── shared.d.ts
    │   └── shared.js
    ├── shared.ts
    └── tsconfig.json

However, upon running node dist/a.js in the A directory, an error is thrown:

module.js:538
    throw err;
    ^
Error: Cannot find module '../Shared/shared'

The issue lies in the unresolved reference to the imported module inside the generated a.js file:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var shared_1 = require("../Shared/shared");
console.log(shared_1.name);

Is there a workaround to resolve this without consolidating all output files into one directory?

Alternatively, are there better practices to organize my project for optimal use of project references?

Answer №1

Dealing with relative import paths for both source files and output files can be quite challenging. The recommended approach, as I understand it, involves setting up a master output directory for the entire composite project with subdirectories like Shared and A. This allows for consistency in the relative layout of both the source and output files. If this is not what you had in mind, there are alternative options available.

One option is to have each component import other components using non-relative imports that point to the output files (e.g., A/a.ts importing from Shared/dist/shared). By using non-relative imports, the same path in both the source and output file will resolve to the correct target output file. Please note that these imports may not resolve in your IDE until the composite project has been built due to a limitation. Since tsc does not rewrite imports, additional setup may be required in your runtime environment or by using a bundler to handle non-relative imports. Adjustments to the baseUrl and paths TypeScript compiler options may also be necessary.

If you encounter any difficulties with either approach, feel free to reach out for assistance. I am more than willing to help guide you through any challenges you may face.

Answer №2

It seems that the official recommendation is to create a main output directory for the entire composite project and include Shared and A subdirectories within it. This way, the source files and output files can maintain the same relative layout.

Matt's response provides helpful insight. Expanding on the previous comment, here is a suggested approach to reconfigure A and Shared for proper functioning of the imported module.

A/tsconfig.json:

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "outDir": "dist/A",
    "strict": true
  },
  "references": [
    { "path": "../Shared" }
  ]
}

Shared/tsconfig.json:

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "outDir": "../A/dist/Shared",
    "composite": true,
    "strict": true
  }
}

The project structure post tsc --build:

https://i.sstatic.net/Lwxc8.png

For executing A, use node dist/A/a.js.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Angular - passing information to a nested component

Within my application, I have a main component along with three sub-components. I am passing data to these three sub-components and using setTimeout to manage the timing of the data being sent. The first sub-component displays for 5000 milliseconds. The ...

How to bring in a class that was exported using `export = uuid` in Typescript

I'm facing a challenge while working with the node_module called uuid-js in TypeScript. After installing both the module and its typings, I am unsure how to properly import the module. Question: What is the correct way to import the module? The func ...

The npm crash is caused by Firestore addDoc

My approach to importing firestore looks like this: import { getFirestore, addDoc } from "firebase/firestore"; However, it seems to be causing issues with npm running my react app as it gets stuck during compilation and eventually shows the foll ...

Is there a way to instruct Babel to generate polyfills such as `__createClass` only once for multiple files?

In my project, I have multiple ES6 files, each containing at least one class. For every file, the __createClass, __interopRequireDefault, and __classCallback polyfilling functions are generated. I plan to concatenate them using browserify, but it seems re ...

What is the proper way to set up @Input?

I attempted to accomplish this in the following manner: @Input() data: any[] = []; Upon entering the ngOnInit lifecycle method, I notice that this.data is undefined: ngOnInit() { console.log(this.data); } Consequently, when trying to access th ...

A guide on utilizing portals in Next.js to move a child element beyond its direct parent container

Current Setup Wrapper export const ContainerComponent = () => { return (<ChildComponent/>); } Child Component export const ChildComponent = () => { return ReactDOM.createPortal( <aside> <div>{"I am a c ...

Encountering an error in Angular2 and TypeScript: TS2322 error message stating that the type 'Response' cannot be assigned to type 'UserStatus'

Currently, I am facing some challenges while working with Angular2 and TypeScript. Transitioning from AngularJS to Angular2 has proven to be a bit tricky for me. To better understand this new framework, I decided to create an experimental app with the foll ...

Error message in React: "The type 'Window & typeof globalThis' does not have a property named 'ethereum'"

Encountering a problem: Issue with 'ethereum' property on type 'Window & typeof globalThis' In my React project, I'm facing an error. The following code is causing the problem: import { ethers } from 'ethers' cons ...

A more efficient way to specify children types in Typescript React is by directly specifying the type in the function instead

What is the reason behind this: interface UserSidebarProps { children? : React.ReactNode } function UserSidebar({children}: UserSidebarProps) { return ( <div> {children} </div> ) } Why doesn't this work? function User ...

Tips for effectively overriding a method in typescript

Why is this.fullName appearing empty in the show() method? class Person { protected name: string = ""; constructor(name: string) { this.makeSir(name); } makeSir(name: string) { this.name = "sir" + name; } } class M ...

Looking to identify the type of a adorned class in Typescript?

Consider the following scenario: return function IsDefined(object: any, propertyName: string) { .... ] We then go ahead and decorate a property like this: class Test { @IsDefined() p1: String = ""; } Now, when we execute a test inside the ...

What is the reason behind RematchDispatch returning a `never` type when a reducer and an effect share the same name?

Recently, I made the switch from TypeScript 4.1.2 to 4.3.2 with Rematch integration. Here are the Rematch packages in use: "@rematch/core": "2.0.1" "@rematch/select": "3.0.1" After the upgrade, a TypeScript error p ...

Testing the GET method in an Angular service: A guide

I'm currently facing an issue with my service method and unit test setup. Despite writing a unit test for the getter method, the coverage report indicates that this method is not covered. I would appreciate any advice on what might be going wrong in m ...

The element 'x' is not found within the 'unknown' type

I've been struggling with this issue. After searching through various sources like stackoverflow and github, I attempted a solution which involved adding a generic but I encountered the error message Expected 0 type arguments, but got 1. in relation t ...

The name "Identifier" has already been declared before

I am currently working on a social network project to enhance my skills in nodejs and reactjs. While debugging the backend code for /signin using Postman, I encountered an error that prevents me from launching the node server. The error message displayed i ...

In the context of NextJs, the req.body is treated as an object within the middleware, but transforms

Here is the middleware function responsible for handling the origin and CORS: export async function middleware(request: NextRequest) { const requestHeaders = new Headers(request.headers) const origin = requestHeaders.get('origin') ?? '& ...

Guide to creating a Map with typescript

I've noticed that many people are converting data to arrays using methods that don't seem possible for me. I'm working with React and TypeScript and I have a simple map that I want to render as a list of buttons. Here is my current progres ...

Harness the power of the Node.js Path module in conjunction with Angular 6

I'm currently facing an issue with utilizing the Path module in my Angular 6 project. After some research, I came across a helpful post detailing a potential solution: https://gist.github.com/niespodd/1fa82da6f8c901d1c33d2fcbb762947d The remedy inv ...

Executing an individual .ts file within a Next.js application using ts-node for the purpose of testing

I'm attempting to execute a single ES module .ts file within a Next.js project using the default configuration for quick debugging: npx ts-node lib/my_module.ts However, I encounter the following error: Warning: To load an ES module, set "type&q ...

I am looking to enhance my array of objects by implementing a filter. It is important that the filter does not allow for duplicate checkboxes with the

My website : On the left-hand side of my webpage, there is a set of checkboxes with some repeated names that I don't want. For example, "Rice" is repeated twice but I only want it to display once. When checking the Rice checkbox, it should show all c ...