Skip to content

ts_project breaks on relative imports to .d.ts source files #3120

@lencioni

Description

@lencioni

🐞 bug report

Affected Rule

The issue is caused by the rule: ts_project

Is this a regression?

No, I don't think so

Description

I am working in a monorepo that uses ts_project roughly as described by #2298

We have run into a build failure when using a relative import to a .d.ts source file.

🔬 Minimal Reproduction

We have a structure like the following:

frontend/a
├── BUILD.bazel
├── index.ts
└── tsconfig.json
frontend/b
├── BUILD.bazel
├── foo.d.ts
├── index.ts
└── tsconfig.json

Here are the contents of those files:

// frontend/a/index.ts
import { PageData } from ':b';

const a: PageData = {
  components: [],
};

export const imageComponent = (a?.components || []).find(
  (component) => component?.componentType === 'IMAGE',
);
// frontend/b/index.ts
import type { ContentPage } from './foo';

export type PageData = ContentPage;
// frontend/b/foo.d.ts
export interface Components {
  readonly componentAttributes: string | null;
  readonly componentType: string | null;
  readonly id: integer | null;
  readonly uuid: string | null;
}

export interface ContentPage {
  readonly components: (Components | null)[] | null;
}

🔥 Exception or Error

In this example, frontend/b is able to build ts_project successfully, but when building frontend/a, which depends on frontend/b for some of its types, we get an error like the following:


frontend/a/index.ts:9:4 - error TS7006: Parameter 'component' implicitly has an 'any' type.

9   (component) => component?.componentType === 'IMAGE',
     ~~~~~~~~~

This error does not happen when running TypeScript outside of bazel.

Looking at the structure of the sandbox, I believe this happens because of the relative import from frontend/b/index.ts to frontend/b/foo.d.ts-- the generated frontend/b/index.d.ts file ends up in the output tree but the frontend/b/foo.d.ts file stays in the source tree. This means that when frontend/b is consumed as a dependency, the relative import from frontend/b/index.ts to ./foo fails, which causes the types to be cast to any, which triggers the error above.

Possibly relevant:

I looked into using copy_file or copy_to_bin in my macro that wraps ts_project for any .d.ts source files, but I didn't have any luck getting it to work the way I wanted and I struggled to find any examples of it being used in this way.

One workaround I found is to add "../../" to compilerOptions.rootDirs, which allows TypeScript to resolve relative imports from the output tree to the source tree. However, I don't want that configuration when not running in Bazel since I think that would cause TypeScript when running outside of Bazel (e.g. in VSCode) to resolve files outside of the repo (and possibly from multiple other repos). One possibility would be to generate tsconfigs with this extra configuration in our macro, but I'd prefer to avoid that complexity if possible (plus, it seems that this may not work with the tsconfig option today since .d.ts files are filtered out in the generated tsconfig file https://github.com/bazelbuild/rules_nodejs/blob/d30c366127c208d14d08adb74f4a847f87558c92/packages/typescript/internal/ts_project.bzl#L672).

At this point I see a few possible resolutions:

  1. Should ts_project just handle .d.ts source files automatically? (e.g. build in copy_to_bin to the rule for .d.ts source files) I think this would be the most ergonomic outcome.
  2. If we don't want ts_project to handle this automatically, it would be really helpful to add an example to the docs of how to compose ts_project with copy_to_bin or something similar (js_library maybe?) to make this scenario work.
  3. If my understanding of copy_to_bin doesn't make sense (which is likely) then it probably makes sense to update the ts_project docs to include "../../" to the compilerOptions.rootDirs configuration along with an example of how to use this safely in a generated tsconfig.json file.

🌍 Your Environment

Operating System:

MacOS 12.0.1

Output of bazel version:

Bazelisk version: v1.10.1
Build target: bazel-out/darwin-opt/bin/src/main/java/com/google/devtools/build/lib/bazel/BazelServer_deploy.jar
Build time: Thu Jan 01 00:00:00 1970 (0)
Build timestamp: Thu Jan 01 00:00:00 1970 (0)
Build timestamp as int: 0

Rules_nodejs version:

(Please check that you have matching versions between WORKSPACE file and @bazel/* npm packages.)

4.4.6

Anything else relevant?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions