package.json “type” field
The "type"
field defines the module format that Node.js uses for all .js
files that have that package.json
file as their nearest parent.
If the nearest parent package.json
lacks a "type"
field, or contains "type": "commonjs"
, .js
files are treated as CommonJS. If the volume root is reached and no package.json
is found, .js
files are treated as CommonJS. In short, all .js
files are treated as CommonJS modules unless "type": "module"
is defined in package.json
.
Node.js uses CommonJS by default, you need to enable the ES module support by setting "type": "module"
in your package.json
file.
Suppose there are two .js
files in your app and they are both written in ES module, the first util.js
:
1 | export function printMessage(msg) { |
And you import it in the main file index.js
,
1 | import { printMessage } from "./util.js"; |
Then if you try to run this file on Node.js, you might encounter an error.
1 | node index.js |
Error:
1 | import printMessage from './util.js'; |
There are two ways to fix this problem. You could rewrite your files into CommonJS format, the other way is to add "type": "module"
in your package.json
file, which is much easier.
1 | // package.json |
Output:
1 | The message is: Hello |
TypeScript also consult the nearest package.json
file to determine the module format when a file with a .js
or .ts
extension.
TSConfig Option: module
field
This is a TypeScript compiler option field which can be found in the tsconfig.json
file. It sets what module code is generated.
Allowed values:
- none
- commonjs
- amd
- umd
- system
- es6/es2015
- es2020
- es2022
- esnext
- node16
- nodenext
You very likely want "nodenext"
for modern Node.js projects, "esnext"
for others.
Here’s some example output for this file:
1 | // @filename: index.ts |
CommonJS
1 | ; |
UMD
1 | (function (factory) { |
AMD
1 | define(["require", "exports", "./constants"], function ( |
System
1 | System.register(["./constants"], function (exports_1, context_1) { |
ESNext
1 | import { valueOfPi } from "./constants"; |
ES2015/ES6/ES2020/ES2022
1 | import { valueOfPi } from "./constants"; |
node16/nodenext
The emitted JavaScript uses either CommonJS
or ES2020
output depending on the file extension and the value of the type
setting in the nearest package.json
. If the value is module
, the format is ES2020
, otherwise CommonJS
.
None
1 | ; |
Include “.js” extension for custom modules
If you want to use the official TypeScript compiler to generate JavaScript, you have to add the extension because
- Node.js refuses to allow extensionless relative imports
- TypeScript refuses to add import extensions at compile time
If you want or need to write extensionless imports in TypeScript, you need a bundler or an alternative build tool that can add the .js
extensions. For example, you can transpile TypeScript to JavaScript using Babel and babel-plugin-add-import-extension.
However, you’ll still need TypeScript (tsc
) itself to do type checking and generate type declaration files, so you’ll need a tsconfig.json
with compilerOptions.moduleResolution
set to "Bundler"
.