Typescript 中导入 JSON 模块

2021-05-16

Typescript 2.9 引入了一个新的 --resolveJsonModule 编译器选项,允许我们在 Typescript 中导入 JSON 模块。

通过 require 导入 JSON 模块

假设我们有个用 Typescript 写的 Node 应用,需要导入下面的 JSON 文件:

{
  "server": {
    "nodePort": 8080
  }
}

在 Node 中,我们可以像其他 CommonJS 模块一样通过 require 导入 JSON 文件:

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

JSON 会自动反序列化为 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} ...`);
});

目前为止都很好。

通过静态 import 声明导入 JSON 文件

现在我们要使用原生的 ECMAScript 模块而不是 CommonJS 模块。这意味着我们需要使用静态 import 声明来替代 require 调用:

// 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} ...`);
});

我们会在第二行发现一个报错。Typescript 默认并不允许我们像这样直接导入 JSON 模块。这是 Typescript 团队有意做出的设计决定:导入一个大的 JSON 文件很可能会消耗大量的内存。所以需要显式地使用 --resolveJsonModule 编译选项来允许导入:

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

让我们打开 tsconfig.json 文件,然后开启 resolveJsonModule 选项:

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

开启 resolveJsonModule 选项后,在我们的 Typescript 文件中不再报错。甚至我们可以得到类型检查和自动补全功能。

如果我们编译上面的 Typescript 代码,我可以得到以下的 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} ...`);
});

注意,输出和我们之前的 require 版本非常相似:

"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} ...`);
});

好了,这就是如何在 Typescript 中导入 JSON 模块,只需要一个编译选项就能搞定。

郑超的独立博客