How would I configure TypeScript in order to take advantage of all the latest features in Node.js 18? Specifically I would like to know how to get full support for ESM, and how to use all the latest syntax and functions introduced in ES2021/ES2022.
1 Answers
As of Node.js 18.0.0
, 100% of ES2022 is supported (apart from a bug in RegEx.flags), and support for ES Modules is stable! If you know that you are targeting that version or newer, the optimal config would look like this:
"module": "ES2022"
&"moduleResolution": "node"
Node.js 18 support loading modules instead of the old CommonJS format, we do have to tell TypeScript that we are using Node.js's rules for resolving modules.
"allowSyntheticDefaultImports": true
To provide backwards compatibility, Node.js allows you to import CommonJS packages with a default import. This flag tells TypeScript that it's okay to use
import
on CommonJS modules."target": "ES2022"
This tells TypeScript that it's okay to output JavaScript syntax with features from ES2022. In practice, this means that it will e.g. output logical assignment operators & async/await syntax instead of embedding a polyfill.
"lib": ["ES2022"]
This tells TypeScript that it's okay to use functions and properties introduced in ES2022 or earlier. In practice, this means that you can use e.g.
Promise.any
andString.prototype.replaceAll
.
The full config would thus be:
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"lib": ["ES2022"],
"module": "ES2022",
"moduleResolution": "node",
"target": "ES2022"
}
}
In addition to this, we also need to tell Node.js to treat .js
files in this project as ES Modules. The reason for this is that Node.js had to maintain backwards compatibility with code written for older Node.js versions. This can be done by adding "type": "module"
to your package.json
:
{
"type": "module"
}
Another change if you are coming from an earlier version of Node.js is that the file extensions when importing files are now mandatory. This means that you must write out .js
at the end of your local imports. Note that this is .js
even though you are importing a TypeScript file that actually has the file extension .ts
. This might seem a bit confusing but this comment from one of the TS contributors explains why that is.
Here are some examples of how to write your import
statements:
// Built-in Node.js modules
import { readFileSync } from 'fs'
// CommonJS packages from Npm
import md5File from 'md5-file'
// The local file "a.ts"
import { a } from './a.js'
If you want to stick with CommonJS for now, to avoid the caveats explained above, you can use the following config:
{
"compilerOptions": {
"lib": ["ES2022"],
"module": "CommonJS",
"target": "ES2022"
}
}
If you are running Node.js 16 you can see my similar answer for Node.js 16 here
If you are running Node.js 14 you can see my similar answer for Node.js 14 here
If you are running Node.js 12 you can see my similar answer for Node.js 12 here
If you are running Node.js 10 you can see my similar answer for Node.js 10 here
If you are running Node.js 8 you can see my similar answer for Node.js 8 here

- 23,234
- 15
- 74
- 89
-
I wanted to point out that namespace imports no longer work either. If you have an `index.ts` in a directory, you'll have to access it directly, e.g.: `import { myUtilFunc } from './utils/index.js`. – Joe Sadoski Jan 30 '23 at 05:36
-
1Hello, I have the above configuration but TypeScript is still complaining about using globals like `fetch` and `Request`, `Cannot find name 'fetch'.ts(2304)` – expandstudios Feb 01 '23 at 00:31
-
@expandstudios have you installed the `@types/node` package at version 18.x? – Linus Unnebäck Feb 01 '23 at 03:12
-
1Why not `"moduleResolution": "node16"`? Can you clarify that? – pkerschbaum Feb 15 '23 at 10:22
-
1Agree with @pkerschbaum Should use "module" and "moduleResolution" of "Node16" and you won't have to worry about rewriting you imports. – Yinzara Mar 22 '23 at 19:53
-
@expandstudios You need to add "dom" into the "lib" if you want to use the Fetch APIs of Node 18. Right now TypeScript doesn't have a lib that supports Node16 or Node18 – Yinzara Mar 22 '23 at 19:55
-
If I set `"type": "module"` then I can't use `require` but there are some packages, e.g. [debugjs](https://github.com/debug-js/debug) is still cmj only. – Qiulang Jul 18 '23 at 03:17