揭秘 tsconfig:module 配置全解析

489 阅读16分钟

module 配置项用于指定生成代码的模块化规范,比如:commonjsumd 、es module (es6、es2020、es2022)等。

当 tsconfig 中 targetes5 时,module 配置项默认为 commonjs (模块格式);否则默认为 es6 (模块格式) 。

在项目里,要正确地设置 TypeScript 中的 module 配置,首先要明确宿主环境所期望的模块类型。例如,不同版本的 Node.js 对模块类型支持情况有所不同,Node.js 11 及更早版本只支持 CommonJs 模块(CJS)。Node.js 12 及更高版本同时支持 CommonJS 模块和 ES 模块,Node.js 会利用文件拓展名以及 package.json 文件来确定每个文件应采用的模块格式,如果文件内容与预期格式不匹配,就会抛出错误。

module 编译器选项的目的就是将宿主环境所期望的模块类型告诉 TypeScript 编译器。他会控制编译过程中所生成的任何 JavaScript 代码的模块格式,也用于告知编译器应如何检测每个文件所属的模块类型、不同模块类型之间如何相互导入,以及像 import.meta 和顶层 await 这类特性是否可用。因此,即便一个 TypeScript 项目设置了 noEmit ,为 module 选项选择正确的设置仍然很重要。因为编译器需要对模块系统有准确的理解,这样他才能对导入进行类型检查(从而提供类型的智能提示,即 IntelliSense)。

module 支持的配置较多,可以说是 tsconfig 中最难理解的配置之一。

module 支持的配置有 node16nodenextpreservees2015 (es6)、es2020es2022esnextcommonjssystemamdumd

下面具体说说每个配置的含义与作用。

node16, nodenext

Node.js 同时支持 CommonJS 和 ECMAScript 模块,对于每种文件可以采用的格式,以及这两种格式如何实现互操作,都有特定的规则。node16nodenext 描述了 Node.js 双格式模块系统的完整行为范围,并且会以 CommonJS 或 ESM 格式输出文件。这与其他所有模块选项都不同,其他模块选项与运行时无关,会强制所有输出文件采用单一格式,由用户来确保输出对其运行时来说是有效的。

一个常见的误解是,node16nodenext 只输出 ES 模块。实际上,node16nodenext 描述的是支持 ES 模块的 Node.js 版本,而不只是使用 ES 模块的项目。基于检测到的每个文件的模块格式,既支持输出 ESM,也支持输出 CommonJS。由于 node16nodenext 是仅有的反映 Node.js 双模块系统复杂性的 module 选项,所以对于所有打算在 Node.js v12 或更高版本中运行的应用程序和库来说,无论它们是否使用 ES 模块,它们都是唯一正确的 module 选项

node16nodenext 目前是相同的,唯一的区别在于它们意味着不同的默认 target 选项值。如果 Node.js 在未来对其模块系统做出重大更改,node16 将被冻结,即维持现有的行为不变,而 nodenext 会被更新以反映新的行为。

隐含与强制的配置

  • modulenodenextnode16 时,会强制要求 moduleResolutionmodule 采用相同的名称。如果不指定 moduleResolution,则默认为 nodenextnode16

62.png

63.png

  • modulenodenext 时,target 默认会为 esnext

  • modulenode16 时,target 默认会为 es2022

  • modulenodenextnode16 时,esModuleInterop 默认为 true

模块格式检测

  • .mts.mjs.d.mts 文件会被认为是 ES 模块
  • .cts.cjs.d.cts 文件会被认为是 CommonJS 模块
  • 如果最近的 package.json 文件包含 "type": "module",则 .ts.tsx.js.jsx.d.ts 文件会被认为是 ES 模块,否则他们会被认为是 CommonJS 模块

检测到的输入 .ts.tsx.mts.cts 文件的模块格式决定了输出 JavaScript 文件的模块格式。例如,一个完全由 .ts 文件组成的项目,当 module 设置为 nodenext 时,默认会输出 CommonJS 模块。但可以通过在 package.json 中设置 "type": "module" 改为输出 ES 模块。

互操作性规则

  • 当一个 ES 模块引用一个 CommonJS 模块时:

    • CommonJS 模块的 module.exports 可以作为默认导入项供 ES 模块使用。
  • 当一个 CommonJS 模块引用一个 ES 模块时

    • require 无法引用 ES 模块。对于 TypeScript 而言,这包括在被检测为 CommonJS 模块的文件中的 import 语句,因为在生成的 JavaScript 代码中,那些 import 语句会被转换为 require 调用。

    • 可以使用动态的 import() 调用导入一个 ES 模块。它返回一个 Promise,该 Promise 解析后得到模块的模块命名空间对象(就如同从另一个 ES 模块中使用 import * as ns from "./module.js" 所获取到的对象一样 )。

不过随着 node.js 22.0.0 版本的发布,CommonJS 模块中也可以使用 require() 命令导入 ES 模块了。不过这个目前还是实验性的特性,因此在执行代码的时候需要加上 --experimental-require-module 标识。

有关更多 ES 模块和 CommonJS 模块互相引用的知识可见JS 模块进阶:ES 模块与 CommonJS 模块的互相引用

生成

每个文件生成的模块格式由每个文件的模块格式检测结果决定。ESM 输出与 --module esnext 类似,但对于 import x = require("...") 有特殊的转换处理,不过在 --module esnext 模式下,这种写法是不被允许的:

// @Filename: main.ts
import x = require("mod");
// @Filename: main.js
import { createRequire as _createRequire } from "module";
const __require = _createRequire(import.meta.url);
const x = __require("mod");

例如这个例子,此例子的目的是演示 CommonJS 模块的代码转换为 ES 模块的代码,此例子的目录结构为:

64.png

index.ts 文件的代码如下:

import u = require('fs')
console.log('u  ', u)

package.json 文件内容如下,并且 "type": "module" 告知 TypeScript 当前是 ESM :

{
  "name": "ts-demo3",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "build": "tsc -b"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@types/node": "^22.10.2",
    "typescript": "^5.7.2"
  }
}

TypeScript 的配置文件 tsconfig.json 内容如下:

{
  "compilerOptions": {
    "baseUrl": ".",
    "outDir": "dist",
    "module": "nodenext"
  },
  "include": ["src"]
}

在终端运行 npm run build 命令,得到 index.js 为:

import { createRequire as _createRequire } from "module";
const __require = _createRequire(import.meta.url);
const u = __require("fs");
console.log('u  ', u);

可以发现 import u = require('fs') 这种写法做了特殊转换处理。

如果将 tsconfig.json 下的 module 修改为 esnext ,可以发现 import u = require('fs') 这种写法是不被允许的:

65.png

CommonJS 的输出与 --module commonjs 类似,但动态 import() 调用不会被转换。此处展示的输出是在启用 esModuleInterop 的情况下的:

// @Filename: main.ts
import fs from "fs"; // transformed
const dynamic = import("mod"); // not transformed
// @Filename: main.js
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = __importDefault(require("fs")); // transformed
const dynamic = import("mod"); // not transformed

接下来看看具体的例子,此例子的目的是演示 ES 模块的代码转成 CommonJS 模块的代码,此例子的目录结构为:

66.png

index.ts 文件的代码如下:

import fs from "fs";
const cmm = import("./common.cjs");

interface Cmm {
  add: (a: number, b: number) => number
}

console.log('fs  ', fs)
cmm.then(r => {
  console.log('r  ', (r as unknown as Cmm).add(1, 2))
})

common.cts 文件代码为:

function add(a: number, b: number) {
  return a + b
}

module.exports.add = add

package.json 文件内容如下,并且 "type": "commonjs" 告知 TypeScript 当前是 CommonJS 模块:

{
  "name": "ts-demo3",
  "version": "1.0.0",
  "description": "",
  "type": "commonjs",
  "main": "index.js",
  "scripts": {
    "build": "tsc -b"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@types/node": "^22.10.2",
    "typescript": "^5.7.2"
  }
}

TypeScript 的配置文件 tsconfig.json 内容如下:

{
  "compilerOptions": {
    "baseUrl": ".",
    "outDir": "dist",
    "useDefineForClassFields": false,
    "module": "nodenext",
    "esModuleInterop": true
  },
  "include": ["src"]
}

在终端运行 npm run build 命令,得到 index.js 为:

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = __importDefault(require("fs")); // transformed
const cmm = import("./common.cjs"); // not transformed
console.log('fs  ', fs_1.default);
cmm.then(r => {
    console.log('r  ', r.add(1, 2));
});

common.cjs 为:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function add(a, b) {
    return a + b;
}
module.exports.add = add;

总结

  • 对于所有打算在 Node.js v12 或更高版本中运行的应用程序和库,无论它们是否使用 ES 模块,node16nodenext 都是唯一正确的 module 选项。

  • node16nodenext 会根据检测到的每个文件的模块格式,以 CommonJS 或 ESM 格式输出文件。

  • Node.js 在 ESM(ES 模块)和 CJS(CommonJS 模块)之间的互操作性规则反映在了类型检查中。

Node.js 对 ES 模块和 CommonJS 模块互操作性的规则被融入到 TypeScript 的类型检查中,用于检查模块间引用是否符合规范,提前发现潜在的运行时错误。

  • ESM 输出会将 import x = require("...") 转换为由 createRequire 导入构造的 require 调用。

  • CommonJS 输出不会转换动态 import()调用,因此 CommonJS 模块可以异步导入 ES 模块。

preserve

在 TypeScript 5.4 中新增了 modulepreserve 模式。

preserve 模式下,输入文件中的 ECMAScript 导入和导出语句会在输出中保留,而 CommonJS 风格的 import x = require("...") 以及 export =... 语句会作为 CommonJS 的 requiremodule.exports 输出。换句话说,每个单独的导入或导出语句的格式都会被保留,而不会在整个编译过程(甚至整个文件)中被强制转换为单一格式。

export =import = require() 是 TypeScript 特有的语法。具体见 模块

来看具体的例子,该例子的目录结构为:

67.png

TypeScript 配置文件 tsconfig.json 如下,将 module 设置为 preserve

{
  "compilerOptions": {
    "baseUrl": ".",
    "outDir": "dist",
    "useDefineForClassFields": false,
    "module": "preserve",
    "esModuleInterop": true
  },
  "include": ["src"]
}

package.json 文件如下:

{
  "name": "ts-demo3",
  "version": "1.0.0",
  "description": "",
  "type": "commonjs",
  "main": "index.js",
  "scripts": {
    "build": "tsc -b"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@types/node": "^22.10.2",
    "typescript": "^5.7.2"
  }
}

my-util.ts 文件的内容为:

const isArr = (list) => {
  return Array.isArray(list)
}
  
export {
  isArr
}

common.cts 文件的内容为,其中使用了 TypeScript 特有的 export = 语法,用于导出 add 函数:

function add(a: number, b: number) {
  return a + b
}

export = {
  add
}

index.ts 文件内容为,其中使用了 TypeScript import = require() 的特有语法:

import { isArr } from './my-util'
import fs = require('fs')
const cmm = import("./common.cjs");

interface Cmm {
  add: (a: number, b: number) => number
}

console.log('fs  ', fs)
console.log('isArr  ', isArr([2, 3]))
cmm.then(r => {
  console.log('r  ', (r as unknown as Cmm).add(1, 2))
})

然后在终端运行 npm run build 命令,得到结果:

68.png

69.png

虽然很少需要在同一个文件中混合使用 importrequire 调用,但这种模块模式最能体现大多数现代打包工具以及 Bun 运行时的功能。

为什么要在意 TypeScript 在使用打包器或 Bun 时的模块输出呢,毕竟你可能还设置了noEmit?TypeScript 的类型检查和模块解析行为会受到它将要输出的模块格式的影响。设置module 会向 TypeScript 提供有关打包器或运行时将如何处理导入和导出的信息,这能确保你在导入值上看到的类型准确反映运行时或打包后的情况。

隐含与强制的配置

  • modulepreservemoduleResolution 配置默认为 bundler

  • modulepreserve ,默认会启用 esModuleInterop

modulepreserve 时,esModuleInterop 选项仅针对其类型检查行为默认启用。当 modulepreserve 时,import 语句永远不会转换为 require 调用,所以 esModuleInterop 不会影响输出的 JavaScript 代码。

es2015, es2020, es2022, esnext

  • 对于打包工具(Webpack、Rollup、Vite 等)、Bun 和 tsx,建议结合 --moduleResolution bundler 使用 esnext

  • 不要用于 Node.js 。对于 Node.js 建议使用 node16nodenextmodule 配置,并搭配 package.json 中设置 "type": "module" ,以便输出 ES 模块格式的代码。

  • 在非声明文件中不允许使用 import mod = require("mod")

在普通的 TypeScript 实现文件(如 .ts.tsx 文件)中不允许使用 import mod = require("mod") 导入形式的语句。这种导入形式是为了在 ES 模块中引入 CommonJS 模块而设计的。在一般的 TypeScript 代码文件中,应该使用 ES 风格的导入语句,例如 import * as mod from "mod"; 或者 import mod from "mod"; (对于默认导出)。

  • es2020 增加了对 import.meta 属性的支持

  • es2022 增加了对顶层 await 的支持。

  • exnext 是不断变化的,包括对 ECMAScript 规范的支持

  • 输出的文件是 ES 模块格式的,但是项目所依赖的库可以是任何模块格式的

例子

// @Filename: main.ts
import x, { y, z } from "mod";
import * as mod from "mod";
const dynamic = import("mod");
console.log(x, y, z, mod, dynamic);
export const e1 = 0;
export default "default export";

编译结果为:

// @Filename: main.js
import x, { y, z } from "mod";
import * as mod from "mod";
const dynamic = import("mod");
console.log(x, y, z, mod, dynamic);
export const e1 = 0;
export default "default export";

commonjs

  • 不建议使用这个配置。建议使用 node16nodenext 配置来为 Node.js 输出 CommonJS 模块的代码

  • 输出的文件是 CommonJS 模块格式的,但是项目所依赖的库可以是任何模块格式的

  • 动态 import() 会被转换为一个 require() 调用的 Promise

  • esModuleInterop 影响默认导入和命名空间导入的输出代码。

例子

下面是 esModuleInterop 设置为 false 时的输出结果

// @Filename: main.ts
import x, { y, z } from "mod";
import * as mod from "mod";
const dynamic = import("mod");
console.log(x, y, z, mod, dynamic);
export const e1 = 0;
export default "default export";
// @Filename: main.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.e1 = void 0;
const mod_1 = require("mod");
const mod = require("mod");
const dynamic = Promise.resolve().then(() => require("mod"));
console.log(mod_1.default, mod_1.y, mod_1.z, mod);
exports.e1 = 0;
exports.default = "default export";
// @Filename: main.ts
import mod = require("mod");
console.log(mod);
export = {
  p1: true,
  p2: false
};
// @Filename: main.js
"use strict";
const mod = require("mod");
console.log(mod);
module.exports = {
  p1: true,
  p2: false
};

system

modulesystem 是专为与 SystemJS 模块加载器配合使用而设计的。

SystemJS 是一个 hookable、基于标准的模块加载器。它提供了一种工作流程,使得为浏览器中的原生 ES 模块生产工作流编写的代码(例如 Rollup 的代码分割构建)可以被转译成 System.register 模块格式,以便在不支持原生模块的老式浏览器中运行,同时几乎以原生模块的速度执行,并支持顶层 await、动态导入、循环引用和实时绑定、import.meta.url、模块类型、导入映射、完整性和内容安全策略,兼容性可追溯到 IE11。

简单点说,SystemJS 使现代 JavaScript 模块(ES 模块)能够在旧版浏览器中高效运行,同时保留了现代功能特性并确保了安全性与兼容性。

要注意的是,SystemJS 也支持对 amd、umd 模块的加载,是通用的模块加载器。

例子

此例子的目录结构为:

70.png

此例子的 TypeScript 配置 tsconfig.json 为:

{
  "compilerOptions": {
    "baseUrl": ".",
    "outDir": "dist",
    "useDefineForClassFields": false,
    "module": "system",
    "target": "es6",
    "paths": {
      "undici-types": ["./node_modules/undici-types/index.d.ts"]
    }
  },
  "include": ["src"]
}

注意上面的 path 配置,如果没有 path 配置,运行编译会报 Cannot find module 'undici-types' 的错误:

参考 [@types/node] Compiler error: Cannot find module 'undici-types' #67406

71.png

package.json 文件内容如下:

{
  "name": "ts-demo3",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "tsc -b"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@types/node": "22.0.0",
    "typescript": "^5.7.2"
  }
}

my-util.ts 文件内容为:

const x = 1
const y = 2
const z = 3

export {
  y,
  z
}

export default x

index.ts 文件内容为:

import x, { y, z } from './my-util'
import * as util from './my-util'
const dynamic = import('./my-util')

console.log(x, y, z, util, dynamic);

export const e1 = 0;
export default "default export";

在终端运行 npm run build 命令,可得编译结果:

// @Filename:my-util.js

System.register([], function (exports_1, context_1) {
    "use strict";
    var x, y, z;
    var __moduleName = context_1 && context_1.id;
    return {
        setters: [],
        execute: function () {
            x = 1;
            y = 2;
            exports_1("y", y);
            z = 3;
            exports_1("z", z);
            exports_1("default", x);
        }
    };
});
// @Filename:index.js

System.register(["./my-util"], function (exports_1, context_1) {
    "use strict";
    var my_util_1, util, dynamic, e1;
    var __moduleName = context_1 && context_1.id;
    return {
        setters: [
            function (my_util_1_1) {
                my_util_1 = my_util_1_1;
                util = my_util_1_1;
            }
        ],
        execute: function () {
            dynamic = context_1.import('./my-util');
            console.log(my_util_1.default, my_util_1.y, my_util_1.z, util, dynamic);
            exports_1("e1", e1 = 0);
            exports_1("default", "default export");
        }
    };
});

amd

amd 全称为 "Asynchronous Module Definition",意思是“异步模块定义”。他采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。

  • 专为像 RequireJS 这样的 AMD 加载器设计。

  • 不建议使用这个配置,建议用打包工具(Webpack、Rollup 等)代替

  • 输出的文件是 AMD 模块,但是项目的依赖项可以是任何模块格式的

  • 支持 outFile 配置

outFile 配置会将多个文件打包到 1 个文件中

例子

此例子的目录结构为:

72.png

此例子的 TypeScript 配置 tsconfig.json 为:

{
  "compilerOptions": {
    "baseUrl": ".",
    "outDir": "dist",
    "useDefineForClassFields": false,
    "module": "amd",
    "target": "es6",
    "paths": {
      "undici-types": ["./node_modules/undici-types/index.d.ts"]
    }
  },
  "include": ["src"]
}

注意上面的 path 配置,如果没有 path 配置,运行编译会报 Cannot find module 'undici-types' 的错误,这一点与上面的 system 一样:

73.png

package.json 文件内容如下:

{
  "name": "ts-demo3",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "tsc -b"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@types/node": "22.0.0",
    "typescript": "^5.7.2"
  }
}

my-util.ts 文件内容为:

const x = 1
const y = 2
const z = 3

export {
  y,
  z
}

export default x

index.ts 文件内容为:

import x, { y, z } from './my-util'
import * as util from './my-util'
const dynamic = import('./my-util')

console.log(x, y, z, util, dynamic);

export const e1 = 0;
export default "default export";

在终端运行 npm run build 命令,可得编译结果:

// @Filename:my-util.js
define(["require", "exports"], function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.z = exports.y = void 0;
    const x = 1;
    const y = 2;
    exports.y = y;
    const z = 3;
    exports.z = z;
    exports.default = x;
});
// @Filename:index.js

define(["require", "exports", "./my-util", "./my-util"], function (require, exports, my_util_1, util) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.e1 = void 0;
    const dynamic = new Promise((resolve_1, reject_1) => { require(['./my-util'], resolve_1, reject_1); });
    console.log(my_util_1.default, my_util_1.y, my_util_1.z, util, dynamic);
    exports.e1 = 0;
    exports.default = "default export";
});

outFile 配置会将多个文件打包到 1 个文件中,修改此例子的 tsconfig.json 文件,将其中的 outDir 去掉,并添加 outFile 配置:

74.png

在终端运行 npm run build 命令,看到多个文件都合并成一个文件输出了:

75.png

// @Filename:main.js

define("my-util", ["require", "exports"], function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.z = exports.y = void 0;
    const x = 1;
    const y = 2;
    exports.y = y;
    const z = 3;
    exports.z = z;
    exports.default = x;
});
define("index", ["require", "exports", "my-util", "my-util"], function (require, exports, my_util_1, util) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.e1 = void 0;
    const dynamic = new Promise((resolve_1, reject_1) => { require(["my-util"], resolve_1, reject_1); });
    console.log(my_util_1.default, my_util_1.y, my_util_1.z, util, dynamic);
    exports.e1 = 0;
    exports.default = "default export";
});

umd

umd 全称为 "Universal Module Definition" ,即通用模块定义,是 javascript 的通用模块化规范,能让 javascript 模块即在浏览器中运行,又在 Node.js 中运行

  • 专为 AMD 或 CommonJS loader(加载器) 设计的

  • 不会暴露一个全局变量

umd 模块通常会暴露一个全局变量,通过该全局变量访问模块内部所有的 API ,但是 TypeScript 编译输出的 umd 模块不会暴露全局变量

  • 不建议使用这个配置,建议用打包工具(Webpack、Rollup 等)代替

  • 生成的文件是 umd 模块,但项目依赖项可以是任何模块格式

例子

此例子的目录结构为:

76.png

此例子的 TypeScript 配置 tsconfig.json 为:

{
  "compilerOptions": {
    "baseUrl": ".",
    "outDir": "dist",
    "module": "umd",
    "target": "es6",
    "paths": {
      "undici-types": ["./node_modules/undici-types/index.d.ts"]
    }
  },
  "include": ["src"]
}

注意上面的 path 配置,如果没有 path 配置,运行编译会报 Cannot find module 'undici-types' 的错误:

77.png

package.json 文件内容如下:

{
  "name": "ts-demo3",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "tsc -b"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@types/node": "22.0.0",
    "typescript": "^5.7.2"
  }
}

my-util.ts 文件内容为:

const x = 1
const y = 2
const z = 3

export {
  y,
  z
}

export default x

index.ts 文件内容为:

import x, { y, z } from './my-util'
import * as util from './my-util'
const dynamic = import('./my-util')

console.log(x, y, z, util, dynamic);

export const e1 = 0;
export default "default export";

在终端运行 npm run build 命令,可得编译结果:

// @Filename:my-util.js

(function (factory) {
    if (typeof module === "object" && typeof module.exports === "object") {
        var v = factory(require, exports);
        if (v !== undefined) module.exports = v;
    }
    else if (typeof define === "function" && define.amd) {
        define(["require", "exports"], factory);
    }
})(function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.z = exports.y = void 0;
    const x = 1;
    const y = 2;
    exports.y = y;
    const z = 3;
    exports.z = z;
    exports.default = x;
});
// @Filename:index.js

(function (factory) {
    if (typeof module === "object" && typeof module.exports === "object") {
        var v = factory(require, exports);
        if (v !== undefined) module.exports = v;
    }
    else if (typeof define === "function" && define.amd) {
        define(["require", "exports", "./my-util", "./my-util"], factory);
    }
})(function (require, exports) {
    "use strict";
    var __syncRequire = typeof module === "object" && typeof module.exports === "object";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.e1 = void 0;
    const my_util_1 = require("./my-util");
    const util = require("./my-util");
    const dynamic = __syncRequire ? Promise.resolve().then(() => require('./my-util')) : new Promise((resolve_1, reject_1) => { require(['./my-util'], resolve_1, reject_1); });
    console.log(my_util_1.default, my_util_1.y, my_util_1.z, util, dynamic);
    exports.e1 = 0;
    exports.default = "default export";
});

总结

module 配置项用于指定生成代码的模块化规范,比如:commonjsumd 、es module (es6、es2020、es2022)等。

module 支持的配置较多,可以说是 tsconfig 中最难理解的配置之一。

module 支持的配置有 node16nodenextpreservees2015 (es6)、es2020es2022esnextcommonjssystemamdumd

78.png