Last updated: Feb 29, 2024
Reading time·5 min
The ts-node error '[ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts"'
occurs when the type
property is set to module
in your package.json
file.
You can solve the error, issue the ts-node
command with the --esm
flag or
remove the "type": "module"
property from your package.json
file.
Here is an example of how the error occurs.
Notice that the type
attribute is set to module
in package.json
.
{ "type": "module", "name": "bobbyhadz-ts", "scripts": { "dev": "ts-node src/index.ts" }, "devDependencies": { "@types/node": "^18.15.5", "ts-node": "^10.9.1", "typescript": "^5.0.2" } }
If I try to issue the npx ts-node my-file.ts
command, the error is raised.
# ⛔️ TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /home/borislav/Desktop/bobbyhadz-ts/src/index.ts npx ts-node my-file.ts
--esm
flag when issuing the ts-node
commandOne way to solve the error is to use the --esm
flag when issuing the ts-node
command.
# ✅ works npx ts-node --esm my-file.ts
You can define a dev
script in your package.json
file to not have to
remember to set the --esm
flag every time.
{ "type": "module", "scripts": { "dev": "ts-node --esm my-file.ts" }, "devDependencies": { "@types/node": "^18.15.5", "ts-node": "^10.9.1", "typescript": "^5.0.2" } }
my-file.ts
placeholder with the path to your entry .ts
file.Make sure you have ts-node
installed and issue the npm run dev
command
instead.
# 👇️ install with NPM npm install ts-node --save-dev # 👇️ or with YARN yarn add ts-node --dev
After installing ts-node
, run the command with npm run dev
.
npm run dev
The --esm
flag is used to enable the ESM (ES Modules) loader.
The
ES Modules loader
enables you to use the ES6 import/export
syntax with ts-node
.
The ES Modules loader can also be enabled with the ts-node-esm
command.
npx ts-node-esm src/index.ts bobbyhadz.com
This is equivalent to using the --loader
flag explicitly.
node --loader ts-node/esm my-file.ts
Depending on your Node.js version, you might get a message that custom ESM loaders is an experimental feature.
tsconfig.json
You can also enable the feature by editing your tsconfig.json file.
This allows you to issue the ts-node
command without setting the --esm
flag.
esm
property to true
experimentalSpecifierResolution
property to node
.{ // 👇️ set these 2 properties inside the ts-node object "ts-node": { "esm": true, "experimentalSpecifierResolution": "node" }, "compilerOptions": { // ... rest } }
You don't have to use the --esm
flag after you enable the feature in your
tsconfig.json
file.
# ✅ Works npx ts-node my-file.ts
If the error persists, make sure you have the following properties set in the
compilerOptions
object in your tsconfig.json
file.
{ "ts-node": { "esm": true, "experimentalSpecifierResolution": "node" }, "compilerOptions": { "esModuleInterop": true, "moduleResolution": "node", "module": "CommonJS", // ... rest } // ... rest }
Setting the esModuleInterop
property to true
is very important.
The
esModuleInterop
option is set to false
by default, which causes it to treat CommonJS modules
similar to ES6 modules. This causes some issues.
Setting esModuleInterop
to true
fixes these issues.
The compilerOptions.module
property is used to specify what module code is
generated.
The property can be set to ESNext
to enable additional APIs that are supported
by
your TypeScript version.
{ // ... rest "compilerOptions": { "module": "ESNext", // ... rest } // ... rest }
"type": "module"
from your package.json
fileYou can also solve the error by removing the type
property from your
package.json
file.
{ "type": "module", // 👈️ remove this line "name": "bobbyhadz-ts", "scripts": { "dev": "ts-node src/index.ts" }, "devDependencies": { "@types/node": "^18.15.5", "ts-node": "^10.9.1", "typescript": "^5.0.2" } }
When the type
property is set to module
, all .js
files in the project are
treated as ES modules.
This can cause issues when using ts-node
as ES Modules have not yet been fully
integrated.
Once you remove the type
property, you can issue the ts-node my-file.ts
command without getting the error.
npx ts-node my-file.ts
If the type
field is omitted or set to commonjs
, all .js
files are treated
as CommonJS.
If you don't want to prefix ts-node
commands with npx
, install the module
globally.
npm install -g ts-node
Now the ts-node
command can be used directly.
ts-node my-file.ts
If removing the type
attribute from your package.json
file causes different
errors, add the attribute back.
{ "type": "module", // 👈️ add this line back "name": "bobbyhadz-ts", "scripts": { "dev": "ts-node src/index.ts" }, "devDependencies": { "@types/node": "^18.15.5", "ts-node": "^10.9.1", "typescript": "^5.0.2" } }
Depending on your setup, you might have to set the NODE_OPTIONS
environment
variable to --loader ts-node/esm
to enable the ES Modules loader feature.
The easiest way to set the environment variable is to do it right before issuing
the ts-node
command.
# for macOS, Linux, Git Bash NODE_OPTIONS="--loader ts-node/esm" node my-file.ts
However, if you run the command on Windows in CMD or PowerShell, you will get an error.
You can use the cross-env package to be able to run the command on all operating systems.
First, install the module by running the following command.
# 👇️ with NPM npm install cross-env # 👇️ with YARN yarn add cross-env
Now, set the command as a script
in your package.json
file.
{ "scripts": { "dev": "NODE_OPTIONS=\"--loader ts-node/esm\" node my-file.ts" } }
Notice that we had to escape the double quotes with backslashes.
You can now run the command with npm run dev
.
npm run dev
Now the command is run with the ESM loader enabled.
tsc
and node
instead of ts-node
If the error persists, try to use the tsc
and node
commands manually instead
of using ts-node
(which combines the two).
npx tsc --outDir dist my-file.ts node dist/my-file.js
The tsc
command is used to convert the .ts
file to a .js
file.
The file is placed in the specified --outDir
(dist
in the example).
The last step is to use the node
command to run the .js
file.
You can also use an ampersand &&
to combine the two commands.
npx tsc --outDir dist my-file.ts && node dist/my-file.js
The .js
file is located in the specified --outDir
.
You can learn more about the related topics by checking out the following tutorials: