Typescript: `import './file.json'`: This module is declared with using 'export ='

Created on 26 Mar 2020  Â·  4Comments  Â·  Source: microsoft/TypeScript

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:

  1. allowSyntheticDefaultImports: true works as expected, but that flag is unsafe and I don't want (need) to use it.
  2. declare module './list.json' {
        const list: string[];
        export default list;
    }
    

Playground Link: repro.zip

Related Issues: https://github.com/microsoft/TypeScript/issues/15146

In Discussion Suggestion

Most helpful comment

I had to do some research:

  • The spec doesn't seem to support loading JSON files yet, can't find any mentions of it
  • Firefox 74 errors out with:
    > Loading module from “./package.json” was blocked because of a disallowed MIME type (“application/json”)
  • Node 13 supports it experimentally
    > When the --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'; >
    Sadly the WHATWG link in Node's docs is a gone from the spec
  • Rollup supports it with a plugin
    > js > import pkg from './package.json'; > console.log(`running version ${pkg.version}`); >
  • Webpack maps it to a require, so import list from './list.json works as expected
  • Browserify doesn't support ES Modules, but I assume that the esm 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.

All 4 comments

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:

  • The spec doesn't seem to support loading JSON files yet, can't find any mentions of it
  • Firefox 74 errors out with:
    > Loading module from “./package.json” was blocked because of a disallowed MIME type (“application/json”)
  • Node 13 supports it experimentally
    > When the --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'; >
    Sadly the WHATWG link in Node's docs is a gone from the spec
  • Rollup supports it with a plugin
    > js > import pkg from './package.json'; > console.log(`running version ${pkg.version}`); >
  • Webpack maps it to a require, so import list from './list.json works as expected
  • Browserify doesn't support ES Modules, but I assume that the esm 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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

MartynasZilinskas picture MartynasZilinskas  Â·  3Comments

Roam-Cooper picture Roam-Cooper  Â·  3Comments

kyasbal-1994 picture kyasbal-1994  Â·  3Comments

manekinekko picture manekinekko  Â·  3Comments

zhuravlikjb picture zhuravlikjb  Â·  3Comments