TypeScript Version: 3.0.0-dev.20180605
Search Terms: TS5055 resolveJsonModule
Code
tsjson> find .
.
./main.ts
./json
./json/myjson.json
./tsconfig.json
./src
./src/test.ts
tsconfig.json:
{
"compilerOptions": {
"target": "es5",
"module": "es2015",
"moduleResolution": "node",
"baseUrl": "./",
"resolveJsonModule": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"noEmitOnError": true
},
"include": [
"main.ts",
"src",
"json"
],
"exclude": [
"node_modules"
]
}
main.ts:
import "test";
src/test.ts:
import myjson from "json/myjson.json";
console.log('hello world!', myjson.message);
export {}
json/myjson.json:
{
"message": "to be continue..."
}
Expected behavior:
compile successful
Actual behavior:
tsjson> tsc
error TS5055: Cannot write file '***/tsjson/json/myjson.json' because it would overwrite input file.
Playground Link:
Related Issues:
the compiler when resolving a .json file will read it and write it again. so you really want to have --outDir
option set to avoid the compiler overwriting you input file.
In this case the error pops out when rollup plugin calls ts.parseConfigFileTextToJson()
-- not when typescript is trying to overwrite the file -- in fact typescript won't be doing any file writes at all, all transpiled code is getting fed to rollup.
I will do a workaround by providing a fake outDir
value, but the check probably doesn't belong in parseConfigFileTextToJson
.
@mhegazy If there is no outDir specified, why should the .json file be duplicated? It's a static resource... is there a way to do this without needing outDir?
@mhegazy, still not feel right: if import a native js module, it won't issue TS5055 error
maybe add an compile option --allowJson(and default to false) like --allowJs for js file?
still not feel right: if import a native js module, it won't issue TS5055 error
cause the compiler does not overwrite .d.ts files. so no issue here.
maybe add an compile option --allowJson(and default to false) like --allowJs for js file?
if you use --allowJs
you will get the same error. once the compiler tries to write a file in the same locations a source file an error is issued. This guarantees there are no user data loss caused by the compiler overwriting an existing file.
yes , import js module and set --allowJs to true would cause TS5055 too. if we know the imported js file do not need to be transformed(compiled), we would set allowJs to false, and i think that is the point to provide allowJs option. json file/module would never need to be transformed, so why not just make them "no emit" by default (and we don't lose anything)?
if we know the imported js file do not need to be transformed(compiled)
well we do not rely know that.
And this is why ts.parseConfigFileTextToJson()
might be a wrong place for the check :)
@mhegazy
the compiler when resolving a .json file will read it and write it again
If the outDir is different, that makes sense. But if not, then why try to overwrite it? .json files are closer to being treated like static assets than javascript, so there isn't a 'build artefact' equivalent here.
this issue should be solved since it makes sence to use "./" as outDir in some cases
@mhegazy why is this issue still marked 'working as intended'?
If this is intended to break all projects that don't specify outDir, then how does that make any sense?
And can you answer why the compiler is attempting to write a static file over the top of itself?
The correct solution here is to not attempt to overwrite a .json file is outDir is not specified, because the default location will be in the same directory. Seems like a pretty simple solution to me.
My actual building of the code involves a special outDir, so thankfully this isn't interfering with my deployment.
However this issue is breaking checkers which are just concerned with ensuring the code is all good and nothing more.
https://github.com/fuse-box/fuse-box-typechecker/issues/53
I have proposed a PR to the a particular checker that essentially ignores all TS5055 checks as a workaround. I don't think this is a good idea, it makes sense for TS to be smarter about this.
Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.
Can this be re-opened and the Working as Intended
label get removed?
If it is really "working as intended", I think there should be some documentation that this feature only works in conjunction with the outDir
option.
It almost seems like it is not intended to be used for common use-cases like:
import { version } from './package.json'
I guess it would be fine if you could somehow ignore TS5055
, but // @ts-ignore
has no power here so people using bare-bones tsc
are out of luck...
Another common use-case.
Let's say I have the following project structure:
package.json
src/*.ts
dist/*.js
If I specify include: src
, outDir: dist
and resolveJsonModule: true
, and import the package.json
version with import { version } from '../package.json'
, then suddenly my dist
directory looks like this:
dist/package.json
dist/src/*.js
Even if that's "working as intended", I think that might surprise a lot of people.
Just hit this as well. The fact that the outDir
option _has_ to be set for resolveJsonModule
to work properly seems like a hack. My use case is a JSON file containing test fixtures which is imported from a test suite. Now my choice is to either output test/
to something like dist-test/
(as src/
would have to be output to dist/
) or simply disable well-typed JSON imports, and I'm a little bummed out about the latter being preferable.
we should be able to tell tsc
to skip outputting json files when nedded with "exclude": "folderWithJson/*"
so what I did was compile to .tmp
and move files to dist
to achieve the desired result of excluding folders with json from typescript compilation.
tsconfig.json:
{
"compilerOptions": {
"baseUrl": ".",
"outDir": ".tmp",
"paths": {
"@static/*": ["static/*"],
// ...
"@controller/*": ["src/controller/*"]
}
}
}
package.json:
{
"_moduleAliases": {
"@static": "static",
// ...
"@controller": "dist/controller"
},
// ...
"scripts": {
"build": "rm -rf dist/*; tsc; mv .tmp/src/* dist;"
}
}
this way relative imports and express statics are preserved as well as all masks (from paths
or _moduleAliases
)
we should be able to tell
tsc
to skip outputting json files when nedded with"exclude": "folderWithJson/*"
I was surprised to find this doesn't work already. I've had to revert to using require
instead of import
to load a json due to this bug. I can't have the json copied to the outDir
as it's not under my rootDir
in the project, it changes the outDir
structure as @MarkTiedemann shows above, and I get a TS6059
error.
When using include
in tsconfig.json
, if the json file is not explicitly included with include
, or is explicitly listed in exclude
, the json should not be copied to outDir
.
Have you tried my method of outputting to a temporary folder and having npm copy contents of .tmp/src
to dist
?
Have you tried my method of outputting to a temporary folder and having npm copy contents of
.tmp/src
todist
?
I'm sure that would work for the normal build case, but I don't think it'll work when tsc is in watch mode, which I use. Ultimately, resolveJsonModule
should respect the include/exclude directives.
Before I found this issue, I also left a comment on #24744 which is still open (I hadn't realized this issue is closed and marked fixed, so this discussion will likely go unnoticed).
You could use npm-watch
for frontend compilation and nodemon
for node apps
Having to explicitly set one option like outDir
to enable other option like resolveJsonModule
is not (in my opinion) something that should be marked as working as intended
. There are many scenarios where, you can't have or do not want to have different outDir
. For example in NativeScript the outDir
is exactly the same which is resulting in that resolveJsonModule
to be unusable with the latest TypeScript version.
I thing that the options should be decoupled - we shouldn't have to mandatory set one option to have another in a working state. Not to mention that you can still set the outDir` to the very same folder and cause the very same bug to reappear (which is creating a third rule - do not set outDir as the project dir...)
I'm using webpack.config.ts
and I would have loved to have this feature to read the dependencies
keys of my package.json
. But for now, the little hack that I'm using is to read the file using Node's tools. Yeah I know not very intuitive and hacky but it is working.
'use strict';
import { readFileSync } from 'fs';
import { resolve } from 'path';
export default {
// ...
externals: Object.keys(JSON.parse(readFileSync(resolve('package.json')).toString()).dependencies),
// ...
};
Another common use-case.
Let's say I have the following project structure:
package.json src/*.ts dist/*.js
If I specify
include: src
,outDir: dist
andresolveJsonModule: true
, and import thepackage.json
version withimport { version } from '../package.json'
, then suddenly mydist
directory looks like this:dist/package.json dist/src/*.js
Even if that's "working as intended", I think that might surprise a lot of people.
This issue has any updates ? or workaround?
this issue should not be closed as there is still people struggling with this. Is not fixed and while working with visual studio is very annoying
If you follow this common use-case, then I have a workaround for importing package.json
without mangling the output directory.
I am able to convert this problematic statement:
import pkg from '../package.json'
into
const pkg = require('../package.json')
Previously, I had used
require(require.resolve('../package.json'))
. I have now found that extra call to be unnecessary. I don't remember why we neededrequire.resolve
, but that at the time our program made some complaints.
One side-effect is you lose access to static type-checking as the compiler doesn't know where the dynamically imported module is from at compile-time.
Most helpful comment
Another common use-case.
Let's say I have the following project structure:
If I specify
include: src
,outDir: dist
andresolveJsonModule: true
, and import thepackage.json
version withimport { version } from '../package.json'
, then suddenly mydist
directory looks like this:Even if that's "working as intended", I think that might surprise a lot of people.