Skip to content

Commit 425cc81

Browse files
authored
Update module docs for 5.4 changes (#3063)
1 parent d110ef7 commit 425cc81

File tree

17 files changed

+100
-39
lines changed

17 files changed

+100
-39
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"@types/react": "16.9.17",
2424
"@types/estree": "0.0.46",
2525
"node-gyp": "5.1.0",
26-
"typescript": "5.0.2",
26+
"typescript": "5.4.5",
2727
"tslib": "2.6.0",
2828
"prettier": "^2.0.2",
2929
"shelljs": "0.8.4",

packages/documentation/copy/en/modules-reference/Reference.md

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,41 @@ const dynamic = import("mod"); // not transformed
272272
- ESM emit transforms `import x = require("...")` to a `require` call constructed from a `createRequire` import.
273273
- CommonJS emit leaves dynamic `import()` calls untransformed, so CommonJS modules can asynchronously import ES modules.
274274
275+
### `preserve`
276+
277+
In `--module preserve` ([added](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-4.html#support-for-require-calls-in---moduleresolution-bundler-and---module-preserve) in TypeScript 5.4), ECMAScript imports and exports written in input files are preserved in the output, and CommonJS-style `import x = require("...")` and `export = ...` statements are emitted as CommonJS `require` and `module.exports`. In other words, the format of each individual import or export statement is preserved, rather than being coerced into a single format for the whole compilation (or even a whole file).
278+
279+
While it’s rare to need to mix imports and require calls in the same file, this `module` mode best reflects the capabilities of most modern bundlers, as well as the Bun runtime.
280+
281+
> Why care about TypeScript’s `module` emit with a bundler or with Bun, where you’re likely also setting `noEmit`? TypeScript’s type checking and module resolution behavior are affected by the module format that it _would_ emit. Setting `module` gives TypeScript information about how your bundler or runtime will process imports and exports, which ensures that the types you see on imported values accurately reflect what will happen at runtime or after bundling. See [`--moduleResolution bundler`](#bundler) for more discussion.
282+
283+
#### Examples
284+
285+
```ts
286+
import x, { y, z } from "mod";
287+
import mod = require("mod");
288+
const dynamic = import("mod");
289+
290+
export const e1 = 0;
291+
export default "default export";
292+
```
293+
294+
```js
295+
import x, { y, z } from "mod";
296+
const mod = require("mod");
297+
const dynamic = import("mod");
298+
299+
export const e1 = 0;
300+
export default "default export";
301+
```
302+
303+
#### Implied and enforced options
304+
305+
- `--module preserve` implies `--moduleResolution bundler`.
306+
- `--module preserve` implies `--esModuleInterop`.
307+
308+
> The option `--esModuleInterop` is enabled by default in `--module preserve` only for its [type checking](https://www.typescriptlang.org/docs/handbook/modules/appendices/esm-cjs-interop.html#allowsyntheticdefaultimports-and-esmoduleinterop) behavior. Since imports never transform into require calls in `--module preserve`, `--esModuleInterop` does not affect the emitted JavaScript.
309+
275310
### `es2015`, `es2020`, `es2022`, `esnext`
276311
277312
#### Summary
@@ -1083,42 +1118,38 @@ Features are listed in order of precedence.
10831118

10841119
`--moduleResolution bundler` attempts to model the module resolution behavior common to most JavaScript bundlers. In short, this means supporting all the behaviors traditionally associated with Node.js’s CommonJS `require` resolution algorithm like [`node_modules` lookups](#node_modules-package-lookups), [directory modules](#directory-modules-index-file-resolution), and [extensionless paths](#extensionless-relative-paths), while also supporting newer Node.js resolution features like [package.json `"exports"`](#packagejson-exports) and [package.json `"imports"`](#packagejson-imports-and-self-name-imports).
10851120

1086-
This is very similar to the behavior of [`node16` and `nodenext`](#node16-nodenext-1) resolving in CommonJS mode, but in `bundler`, the conditions used to resolve package.json `"exports"` and `"imports"` are always `"types"` and `"import"`. To understand why, let’s compare against what happens to an import in a `.ts` file in `nodenext`:
1121+
It’s instructive to think about the similarities and differences between `--moduleResolution bundler` and `--moduleResolution nodenext`, particularly in how they decide what conditions to use when resolving package.json `"exports"` or `"imports"`. Consider an import statement in a `.ts` file:
10871122

10881123
```ts
10891124
// index.ts
10901125
import { foo } from "pkg";
10911126
```
10921127

1093-
In `--module nodenext --moduleResolution nodenext`, the `--module` setting first [determines](#module-format-detection) whether the import will be emitted to the `.js` file as an `import` or `require` call and passes that information to TypeScripts module resolver, which decides whether to match `"import"` or `"require"` conditions accordingly. This ensures TypeScripts module resolution process, although working from input `.ts` files, reflects what will happen in Node.js’s module resolution process when it runs the output `.js` files.
1128+
Recall that in `--module nodenext --moduleResolution nodenext`, the `--module` setting first [determines](#module-format-detection) whether the import will be emitted to the `.js` file as an `import` or `require` call, then passes that information to TypeScripts module resolver, which decides whether to match `"import"` or `"require"` conditions in `"pkg"`s package.json `"exports"` accordingly. Lets assume that theres no package.json in scope of this file. The file extension is `.ts`, so the output file extension will be `.js`, which Node.js will interpret as CommonJS, so TypeScript will emit this `import` as a `require` call. So, the module resolver will use the `require` condition as it resolves `"exports"` from `"pkg"`.
10941129

1095-
When using a bundler, on the other hand, the bundler typically processes the raw `.ts` files directly and runs its module resolution process on the untransformed `import` statement. In this scenario, it doesn’t make a lot of sense to think about how TypeScript will emit the `import`, because TypeScript isn’t being used to emit anything at all. As far as the bundler is concerned, `import`s are `import`s and `require`s are `require`s, so the conditions used to resolve package.json `"exports"` and `"imports"` are determined by the syntax seen in the input `.ts` file. Likewise, the conditions TypeScript’s module resolution process uses in `--moduleResolution bundler` are _also_ determined by the input syntax in input TypeScript files—it’s just that `require` calls are not currently resolved at all:
1130+
The same process happens in `--moduleResolution bundler`, but the rules for deciding whether to emit an `import` or `require` call for this import statement will be different, since `--moduleResolution bundler` necessitates using [`--module esnext`](#es2015-es2020-es2022-esnext) or [`--module preserve`](#preserve). In both of those modes, ESM `import` declarations always emit as ESM `import` declarations, so TypeScripts module resolver will receive that information and use the `"import"` condition as it resolves `"exports"` from `"pkg"`.
10961131

1097-
```ts
1098-
// Some library file:
1099-
declare function require(module: string): any;
1132+
This explanation may be somewhat unintuitive, since `--moduleResolution bundler` is usually used in combination with `--noEmit`—bundlers typically process raw `.ts` files and perform module resolution on untransformed `import`s or `require`s. However, for consistency, TypeScript still uses the hypothetical emit decided by `module` to inform module resolution and type checking. This makes [`--module preserve`](#preserve) the best choice whenever a runtime or bundler is operating on raw `.ts` files, since it implies no transformation. Under `--module preserve --moduleResolution bundler`, you can write imports and requires in the same file that will resolve with the `import` and `require` conditions, respectively:
11001133

1134+
```ts
11011135
// index.ts
1102-
import { foo } from "pkg"; // Resolved with "import" condition
1103-
import pkg2 = require("pkg"); // Not allowed
1104-
const pkg = require("pkg"); // Not an error, but not resolved to anything
1105-
// ^? any
1136+
import pkg1 from "pkg"; // Resolved with "import" condition
1137+
import pkg2 = require("pkg"); // Resolved with "require" condition
11061138
```
11071139

1108-
Since TypeScript doesn’t currently support resolving `require` calls in `--moduleResolution bundler`, everything it _does_ resolve uses the `"import"` condition.
11091140

11101141
#### Implied and enforced options
11111142

1112-
- `--moduleResolution bundler` must be paired with the `--module esnext` option.
1143+
- `--moduleResolution bundler` must be paired with `--module esnext` or `--module preserve`.
11131144
- `--moduleResolution bundler` implies `--allowSyntheticDefaultImports`.
11141145

11151146
#### Supported features
11161147

11171148
- [`paths`](#paths) ✅
11181149
- [`baseUrl`](#baseurl) ✅
11191150
- [`node_modules` package lookups](#node_modules-package-lookups) ✅
1120-
- [package.json `"exports"`](#packagejson-exports) ✅ matches `types`, `import`
1121-
- [package.json `"imports"` and self-name imports](#packagejson-imports-and-self-name-imports) ✅ matches `types`, `import`
1151+
- [package.json `"exports"`](#packagejson-exports) ✅ matches `types`, `import`/`require` depending on syntax
1152+
- [package.json `"imports"` and self-name imports](#packagejson-imports-and-self-name-imports) ✅ matches `types`, `import`/`require` depending on syntax
11221153
- [package.json `"typesVersions"`](#packagejson-typesversions) ✅
11231154
- [Package-relative paths](#package-relative-file-paths) ✅ when `exports` not present
11241155
- [Full relative paths](#relative-file-path-resolution) ✅

packages/documentation/copy/en/project-config/Compiler Options.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -809,7 +809,7 @@ tsc app.ts util.ts --target esnext --outfile index.js
809809

810810
<tr class='even' name='module'>
811811
<td><code><a href='/tsconfig/#module'>--module</a></code></td>
812-
<td><p><code>none</code>, <code>commonjs</code>, <code>amd</code>, <code>umd</code>, <code>system</code>, <code>es6</code>/<code>es2015</code>, <code>es2020</code>, <code>es2022</code>, <code>esnext</code>, <code>node16</code>, or <code>nodenext</code></p>
812+
<td><p><code>none</code>, <code>commonjs</code>, <code>amd</code>, <code>umd</code>, <code>system</code>, <code>es6</code>/<code>es2015</code>, <code>es2020</code>, <code>es2022</code>, <code>esnext</code>, <code>node16</code>, <code>nodenext</code>, or <code>preserve</code></p>
813813
</td>
814814
<td><p><code>CommonJS</code> if <a href="#target"><code>target</code></a> is <code>ES3</code> or <code>ES5</code>; <code>ES6</code>/<code>ES2015</code> otherwise.</p>
815815
</td>

packages/documentation/scripts/types/AllFilenames.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export type AllDocsPages =
5757
| "modules-reference/diagrams/esm-cjs-interop.md"
5858
| "modules-reference/diagrams/esm-cjs-interop.md-1.svg"
5959
| "modules-reference/diagrams/esm-cjs-interop.md-2.svg"
60+
| "modules-reference/diagrams/mermaid.config.json"
6061
| "modules-reference/diagrams/theory.md"
6162
| "modules-reference/diagrams/theory.md-1.svg"
6263
| "modules-reference/diagrams/theory.md-2.svg"
@@ -124,6 +125,8 @@ export type AllDocsPages =
124125
| "release-notes/TypeScript 5.0.md"
125126
| "release-notes/TypeScript 5.1.md"
126127
| "release-notes/TypeScript 5.2.md"
128+
| "release-notes/TypeScript 5.3.md"
129+
| "release-notes/TypeScript 5.4.md"
127130
| "tutorials/ASP.NET Core.md"
128131
| "tutorials/Angular.md"
129132
| "tutorials/Babel with TypeScript.md"

packages/playground/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"rootDir": "./src",
1313
"strict": true,
1414
"moduleResolution": "node",
15-
"esModuleInterop": true
15+
"esModuleInterop": true,
16+
"skipLibCheck": true,
1617
}
1718
}

packages/sandbox/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"strict": true,
1414
"allowJs": true,
1515
"moduleResolution": "node",
16-
"esModuleInterop": true
16+
"esModuleInterop": true,
17+
"skipLibCheck": true
1718
}
1819
}

packages/ts-twoslasher/test/results/compiler_errors.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
},
3434
{
3535
"text": "(method) Console.log(...data: any[]): void",
36-
"docs": "",
36+
"docs": "[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)",
3737
"start": 28,
3838
"length": 3,
3939
"line": 2,

packages/ts-twoslasher/test/results/compiler_flags.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
},
3434
{
3535
"text": "(method) Console.log(...data: any[]): void",
36-
"docs": "",
36+
"docs": "[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)",
3737
"start": 80,
3838
"length": 3,
3939
"line": 3,

packages/ts-twoslasher/test/results/completions.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@
146146
},
147147
{
148148
"text": "(method) Console.log(...data: any[]): void",
149-
"docs": "",
149+
"docs": "[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)",
150150
"start": 8,
151151
"length": 3,
152152
"line": 0,

packages/ts-twoslasher/test/results/highlighting.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
},
6161
{
6262
"text": "(method) Console.log(...data: any[]): void",
63-
"docs": "",
63+
"docs": "[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)",
6464
"start": 55,
6565
"length": 3,
6666
"line": 1,

0 commit comments

Comments
 (0)