In short, JSON files's implied type definition is always defined via export =, even if I'm using module: es2015, causing it to error unless I use an unnecessary flag (allowSyntheticDefaultImports)
TypeScript Version: 3.9.0-dev.20200326
Search Terms:
import require json module commonjs es2015
Code
import list from "./list.json";
for (const item of list) {
console.log(item)
}
```json
{
"compilerOptions": {
"outDir": "distribution",
"target": "es2017",
"module": "es2015",
"moduleResolution": "node",
"resolveJsonModule": true,
"strict": true
},
"files": [
"index.ts"
]
}
**Expected behavior:**
`list` is of type `string[]`
**Actual behavior:**
```rb
index.ts:1:8 - error TS1259: Module '"./list"' can only be default-imported using the 'allowSyntheticDefaultImports' flag
1 import list from "./list.json";
~~~~
list.json:1:1
1 [
~
This module is declared with using 'export =', and can only be used with a default import when using the 'allowSyntheticDefaultImports' flag.
Found 1 error.
Workaround:
allowSyntheticDefaultImports: true works as expected, but that flag is unsafe and I don't want (need) to use it.declare module './list.json' {
const list: string[];
export default list;
}
Playground Link: repro.zip
Related Issues: https://github.com/microsoft/TypeScript/issues/15146
I also tried:
import * as list from './list.json;
While that works, it shouldn't. list isn't an iterable at all in this case, and it's a runtime error.
What module loaders present JSON objects via the default export instead of top-level export? Or does the file look like
{
"default": (something)
}
?
I had to do some research:
--experimental-json-modules flag is included both the commonjs and module mode will use the new experimental JSON loader. The imported JSON only exposes a default, there is no support for named exports.js
> import packageConfig from './package.json';
>js
> import pkg from './package.json';
> console.log(`running version ${pkg.version}`);
>require, so import list from './list.json works as expectedesm module does what Webpack does.Ultimately, I think that TypeScript’s behavior is correct since import './file.json' is technically invalid, even though experimentally supported in some places.
The right flag to enable support (at the moment) seems to be allowSyntheticDefaultImports — it makes TS work and it generates invalid code, as expected.
Since both Webpack and node import without the * as x (and for good reasons, seemingly https://github.com/webpack/webpack/issues/8504#issuecomment-447569374) would it make sense to provide an option for resolveJsonModule to support the same semantics?
It's very sad that we have to stick with target=es5 in order to profit from the auto completion support for imported json files when using webpack.
Most helpful comment
I had to do some research:
> Loading module from “./package.json” was blocked because of a disallowed MIME type (“application/json”)
> When the
--experimental-json-modulesflag is included both the commonjs and module mode will use the new experimental JSON loader. The imported JSON only exposes a default, there is no support for named exports.>
js > import packageConfig from './package.json'; >Sadly the WHATWG link in Node's docs is a gone from the spec
>
js > import pkg from './package.json'; > console.log(`running version ${pkg.version}`); >require, soimport list from './list.jsonworks as expectedesmmodule does what Webpack does.Ultimately, I think that TypeScript’s behavior is correct since
import './file.json'is technically invalid, even though experimentally supported in some places.The right flag to enable support (at the moment) seems to be
allowSyntheticDefaultImports— it makes TS work and it generates invalid code, as expected.