DEV Community

Krzysztof Platis
Krzysztof Platis

Posted on • Updated on

Relative import from lib's secondary entry point Error TS5055: Cannot write file X.d.ts because it would overwrite input file

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. 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:

import { X } from './child-entry-point/and/internal/file`;
Enter fullscreen mode Exit fullscreen mode

✅ Good:

import { X } from '@namespace/parent-entry-point/child-entry-point’;
Enter fullscreen mode Exit fullscreen mode

What does TS5055 error mean?

The TypeScript error TS5055 occurs when 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
Enter fullscreen mode Exit fullscreen mode

And here's the source code of Typescript files:

@lib/A

// a.ts
import { b } from '@lib/A/B';
import { c } from './C/c.ts'`; // BAD! path to internal file of @lib/A/C
Enter fullscreen mode Exit fullscreen mode

@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

// b.ts
import { c } from '@lib/A/C';
export const b = 'b';
Enter fullscreen mode Exit fullscreen mode

@lib/A/B depends on @lib/A/C.

@lib/A/C

// c.ts
export const c = 'c';
Enter fullscreen mode Exit fullscreen mode

@lib/A/C is independent.

Building the library and getting the error

Now let’s build our lib:

$ ng build --prod A
Enter fullscreen mode Exit fullscreen mode

ng-packgr will build the entry points in the following order:

  1. ✔️ succesfull compilation of @lib/A/C produces dist/A/C/c.d.ts
  2. ✔️ succesfull compilation of @lib/A/B produces dist/A/B/b.d.ts
  3. ❌ 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 of the above error in the real world library (when running yarn build:libs).

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. Many thanks!

Top comments (0)