Importing JSON Modules in TypeScript
Tags: javascript, typescript, require, node
Published: 2020-02-20 00:59:56

### tl;dr

- There's a new TypeScript flag/config called `--resolveJsonModule` that lets us import a `JSON` using static imports.
- With `--resolveJsonModule` enabled, we'll be able to have autocompletion from out JSON file props.

 
TypeScript 2.9 introduced a new `--resolveJsonModule` compiler option that lets us import JSON modules from within TypeScript modules.

## Importing JSON Modules via require Calls

Let's assume we have a Node application written in TypeScript, and let's say that we want to import the following JSON file:

```json
{
  "server": {
    "nodePort": 8080
  }
}
```

In Node, we can use a `require` call to import this JSON file like any other CommonJS module:

```javascript
const config = require("./config.json");
```

The JSON is automatically deserialized into a plain JavaScript object. This allows us to easily access the properties of our config object:

```javascript
"use strict";

const express = require("express");
const config = require("./config.json");

const app = express();

app.listen(config.server.nodePort, () => {
  console.log(`Listening on port ${config.server.nodePort} ...`);
});
```

So far, so good!

## Importing JSON Files via Static import Declarations

Let's now say we want to use native ECMAScript modules instead of CommonJS modules. This means we'll have to convert our `require` calls to static `import` declarations:


```javascript
// We no longer need the "use strict" directive since
// all ECMAScript modules implicitly use strict mode.

import * as express from "express";
import * as config from "./config.json";

const app = express();

app.listen(config.server.nodePort, () => {
  console.log(`Listening on port ${config.server.nodePort} ...`);
});

```

Now, we get a type error in line 2. TypeScript doesn't let us import a JSON module out of the box, just like that. This was a conscious design decision made by the TypeScript team: pulling in large JSON files could potentially [consume a lot of memory](https://github.com/Microsoft/TypeScript/pull/22167#issuecomment-385479553), which is why we need to opt into that feature by enabling the `--resolveJsonModule` compiler flag:

> Having people to consciously opt into this would imply the user understands the cost.

Let's head over to our `tsconfig.json` file and enable the resolveJsonModule option there:

```json
{
  "compilerOptions": {
    "target": "es2015",
    "module": "commonjs",
    "strict": true,
    "moduleResolution": "node",
    "resolveJsonModule": true
  }
```

With `--resolveJsonModule` enabled, we no longer get a type error in our TypeScript file. Even better, we now get type checking and autocompletion!

If we compile our TypeScript file with the compiler options shown above, we get the following JavaScript output:

```javascript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const express = require("express");
const config = require("./config.json");
const app = express();
app.listen(config.server.nodePort, () => {
    console.log(`Listening on port ${config.server.nodePort} ...`);
});
```

Notice that the output is pretty much identical to our initial `require` version:

```javascript
"use strict";

const express = require("express");
const config = require("./config.json");

const app = express();

app.listen(config.server.nodePort, () => {
  console.log(`Listening on port ${config.server.nodePort} ...`);
});
```

And there you go! This is how to import JSON modules from within TypeScript modules, only one compiler option away.

Happy coding!