Open pyrocat101 opened 9 months ago
Yeah I think technically this is a typescript tsc issue, in that it doesn't copy the .json
inputs to the --outDir
last time I researched it. I think we could copy the file ourselves as a separate action, but it feels like a workaround, so someone should understand at least whether this is a bug in typescript first. Do you have some time to contribute?
Ah, first of all it took me a while to repro within rules_ts because we set --skipLibCheck
on all our tsc invocations.
I see https://github.com/aspect-build/rules_ts/commit/12012a4bbc32237ae002ba4950b8ef5ffad340d9 actually added the explicit .json outputs, so my previous comment was wrong.
It looks like that PR put the .json outputs into the "js" output group, rather than the "types".
I have spent a few hours digging into this, and I'm still not sure it's possible. https://github.com/microsoft/TypeScript/issues/24744 is the open issue in TypeScript that reflects the underlying constraint.
TypeScript handles .json
files under --resolveJsonModule
in a way that's not the same as other typings.
Here's the repro for reference: https://github.com/aspect-build/rules_ts/compare/i516
It's easy to repro by cloning the i516
branch and bazel build //examples/resolve_json_module/bar
.
@gzm0 does this make sense to you? Any ideas?
.json
files are output even with declaration=False, so it's correct that we model them as js_outs
in #322. It wouldn't be the right answer to just treat them as typings instead.
We can include those .json files in the typings output_group
and transitive_declarations as well, see the second commit on that PR. That way they are propagated through the declarations provider to dependent actions where they should be available as inputs to the program.
--- a/ts/private/ts_project.bzl
+++ b/ts/private/ts_project.bzl
@@ -210,7 +210,13 @@ This might be because
This is an error because Bazel does not run actions unless their outputs are needed for the requested targets to build.
""")
- output_declarations = typings_outs + typing_maps_outs + typings_srcs
+ output_declarations = typings_outs + typing_maps_outs + typings_srcs + [
+ # Probably not the right spot: make .json outputs also appear in typings
+ # so they are propagated to dependents and available for typechecking
+ s
+ for s in output_sources
+ if s.path.endswith(".json") and ctx.attr.resolve_json_module
+ ]
# Default outputs (DefaultInfo files) is what you see on the command-line for a built
# library, and determines what files are used by a simple non-provider-aware downstream
(note, we have to patch this after the "Add JS inputs that collide with outputs" occurs, since data.json -> data.json couldn't be pre-declared)
tsc
thinks that any .json
files in the program should be emitted, and emitted files must come from sources that are under the --rootDir. So when .json files appear in the program we get an errorexamples/resolve_json_module/index.d.ts(1,18): error TS6059: File '/private/var/tmp/_bazel_alexeagle/7de78b5a870ca0b5cd7d0aaac8b73a00/sandbox/darwin-sandbox/7/execroot/aspect_rules_ts/bazel-out/darwin_arm64-fastbuild/bin/examples/resolve_json_module/data.json' is not under 'rootDir' '/private/var/tmp/_bazel_alexeagle/7de78b5a870ca0b5cd7d0aaac8b73a00/sandbox/darwin-sandbox/7/execroot/aspect_rules_ts/bazel-out/darwin_arm64-fastbuild/bin/examples/resolve_json_module/bar'. 'rootDir' is expected to contain all source files.
This error doesn't happen for other files we got from _gather_declarations_from_js_providers
because TypeScript doesn't try to emit anything for those. See https://github.com/microsoft/TypeScript/issues/38015#issuecomment-617433717
Assuming no fix in tsc
, we would need a way to provide a type-definition for data.json
without the program containing an emittable file for it.
Apparently there's a new feature in TypeScript 5.0
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-0.html#allowarbitraryextensions
Which lets you specify a data.d.json.ts
file: https://github.com/microsoft/TypeScript/issues/52994
The problem with that is, we don't know how to produce such a file. I think that feature is intended for users to write such a thing by hand.
I think the fix we want to argue for (and likely send a PR) is that the "special case" mentioned in https://github.com/microsoft/TypeScript/issues/38015#issuecomment-617433717 should be extended. There are two ways I'd argue this:
.json
file is in the Program only because it is referenced in a type-only position, i.e. only reachable through import type
. Then the .json
file is excluded from emit. (Note, in the repro this isn't sufficient since the index.ts
used the data
as a value).json
file is outside the rootDir
then the emit should be skipped rather than throw a TS6059
. Avoid having to know whether it is used as a value.@pyrocat101 I suspect we can patch this second behavior into your tsc.js
binary pretty easily as a workaround.
TY for pinging me on this @alexeagle.
We have run into this issue as well. What works as a workaround for us, is to assign the JSON into an intermediate variable:
// foo/foo.ts
import jsonData from './data.json';
const data = jsonData;
export type Data = typeof data;
We are using this for the JSON values but it seems to work as well for types (verified on the i516 branch).
What is happening is that when compiling foo.ts
typescript will actually dump the inferred type of jsonData
into foo.d.ts
:
-import data from './data.json';
+declare const data: {
+ a: string;
+}[];
export declare const a: string;
export declare type Data = typeof data;
+export {};
IDK why the export {};
appears, but most importantly, the declaration does not import the JSON anymore.
I'll have a closer look at the references @alexeagle posted. This does feel like a tsc issue to me, I'll attempt to reproduce this issue without bazel (just tsc -p <path>
).
One thing that stands out for me in all the repros I've seen (not the one we have internally) is that bazel ts_project
's and tsconfig.json
's do not have a 1:1 mapping (and project references are not used). However, I'm unsure to what extent we should expect this to be an issue.
I can reproduce this issue without bazel:
bazel run @pnpm -- install --dir=$PWD/examples
cd examples/resolve_json_module
npx tsc -b bar
foo/index.ts:1:22 - error TS6307: File '/home/tos/gh/rules_ts/examples/resolve_json_module/foo/data.json' is not listed within the file list of project '/home/tos/gh/rules_ts/examples/resolve_json_module/foo/tsconfig.json'. Projects must list all files or use an 'include' pattern.
1 import jsonData from './data.json'
~~~~~~~~~~~~~
Found 1 error.
It seems this is essentially an occurrence of https://github.com/microsoft/TypeScript/issues/25636
The workaround seems to be to simply configure all json files in include
. Which IMHO is:
tsconfig.json
and package.json
to just name 2). So including them by default is meh.IIUC the situation correctly, IMHO the proper fix would be that typescript does not rely on JSON imports for types in its generated .d.ts
files. (This is likely also better from an incremental compilation POV, since types on JSON have to be inferred).
Thanks @gzm0 - that workaround has the right shape IMO. Getting the type signature inlined (like --isolatedDeclarations proposal?) does improve incrementality too - if you change values in data.json
but not types, it doesn't cause a cascading rebuild of ts_project that would have to take the .json as an input.
You mean https://github.com/microsoft/TypeScript/issues/47947 ? IIUC this would be huge for bazel, since we could avoid forwarding all declaration files of the dependencies.
Ah thanks. @gzm0's workaround works well enough for my use case.
What happened?
When
resolveJsonModule
is set, TypeScript type check will read JSON files to infer the types. For example:Type checking
//bar
will throw an error thatdata.json
cannot be resolved. The file is not present in the runfiles because only.d.ts
files offoo
are present.Version
Development (host) and target OS/architectures:
Output of
bazel --version
: aspect 5.8.19Version of the Aspect rules, or other relevant rules from your
WORKSPACE
orMODULE.bazel
file: rules_ts 2.1.0, rules_js 1.34.0Language(s) and/or frameworks involved: TypeScript
How to reproduce
Minimal repro: https://github.com/pyrocat101/ts-json-repro
Any other information?
No response