Relative import from lib's secondary entry point Error TS5055: Cannot write file X.d.ts because it would overwrite input file
Tags: angular, typescript, library, 5days5blogposts
Published: 2021-04-22 20:46:16

**You might see the build error `TS5055` due to various reasons. It can happen for instance when building an Angular library containing [secondary entry points](https://github.com/ng-packagr/ng-packagr/blob/32f1bbb4c311f6b12e56afc1a1e2fa20c8314102/docs/secondary-entrypoints.md). Especially when the parent entry point imports items via a relative path from the secondary entry point's internal file. Instead, it should import items only via the secondary entry point's id.**

**❌ Bad:** 
```typescript
import { X } from './child-entry-point/and/internal/file`;
```

**✅ Good:**
```typescript
import { X } from '@namespace/parent-entry-point/child-entry-point’;
```

### What does TS5055 error mean?

The TypeScript error `TS5055` occurs [when](https://github.com/microsoft/TypeScript/blob/f6d425e1e3fb4f52a2935a8d7f7c2133ccbcb63f/src/compiler/program.ts#L3320) the build of a package outputs a file (i.e. `xxx.d.ts`) which has existed and was already an input (a dependency) for building that package.

### 3 entry points and one faulty import path

Let's take an example, where such an error occurs. Say, our library has 1 primary entry point `@lib/A` and 2 secondary entry points: `@lib/A/B`, `@lib/A/C`:
```
A/
├── a.ts
├── ng-package.json
├── B/
│   ├── b.ts
│   └── ng-package.json
└── C/
    ├── c.ts
    └── ng-package.json
```

And here's the source code of Typescript files:

#### @lib/A
```typescript
// a.ts
import { b } from '@lib/A/B';
import { c } from './C/c.ts'`; // BAD! path to internal file of @lib/A/C
```
`@lib/A` depends on `@lib/A/B`. But it DOES NOT depend on `@lib/A/C`, because the file `./C/c.ts` is imported relatively, as **the source code** of the `@lib/A`.

#### @lib/A/B
```typescript
// b.ts
import { c } from '@lib/A/C';
export const b = 'b';
```
`@lib/A/B` depends on `@lib/A/C`.

#### @lib/A/C
```typescript
// c.ts
export const c = 'c';
```
`@lib/A/C` is independent.

### Building the library and getting the error
Now let’s build our lib:
```bash
$ ng build --prod A
```
[ng-packgr](https://github.com/ng-packagr/ng-packagr) will build the entry points in the following order:
1. ✔️ succesfull compilation of `@lib/A/C` produces `dist/A/C/c.d.ts`
1. ✔️ succesfull compilation of `@lib/A/B` produces `dist/A/B/b.d.ts` 
1. ❌ compilation of `@lib/A` throws the error: `TS5055: Cannot write file 'dist/A/C/c.d.ts' because it would overwrite input file`

Why `dist/A/C/c.d.ts` was both the input and output file for the build of `@lib/A`?
- The input typings for building `@lib/A` are both: `/dist/A/B/b.d.ts` and `/dist/A/C/c.d.ts`. It's because `@lib/A` depends on `@lib/A/B` and  indirectly also on `@lib/A/C` (as `@lib/A/B` depends on `@lib/A/C`).
- The source code of `@lib/A` references directly an internal file from the directory `./C`. So the build produces not only `/dist/A/a.d.ts`, but also attempts to produce `/dist/A/C/c.d.ts` file. And this causes the error, because `/dist/A/C/c.d.ts` has been already the input typing!

### Real example
Here's a [fix](https://github.com/SAP/spartacus/commit/fccf4df94373f8e853a86110ef8487743356aae2#diff-8fb1fe1f3428158329c4ea10b314b449fc7931ecc4d9c5282bdbac234cdf5f45R2-R3) of the above error in the real world library <sup>(when running `yarn build:libs`)</sup>.

### How to prevent a relative path import from a secondary entry point?
As of now, I don’t know. 

Do you know any linter enforcing imports only from secondary entry point's id? **I'm super happy to learn about it**! In that case, please **let me know** in a comment or message me on [twitter](https://twitter.com/krisplatis). Many thanks!