Suggestion: always run ".ts" files. Don't ever say .ts is unknown.
Desired Behavior
There's a whole bunch of closed tickets, online discussion, workarounds, etc. for this:
$ npx ts-node somefile.ts
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts"
Regardless of the contents of package.json, the ERR_UNKNOWN_FILE_EXTENSION is not a logical error for a program whose only purpose is to run TypeScript files.
Thanks for understanding the frustration of the many people that have tried to use ts-node to run a .ts file and been told this isn't possible.
Is this request related to a problem?
$ npx ts-node somefile.ts
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts"
Additional context
Other tools like esrun have been created precisely because of this issue. Rather than close every ticket with 'user error' it would be better if ts-node ran ts files, just like python runs python files and ruby runs ruby files and bash runs bash files.
I even lean towards saying that when running a ts file ts-node should automatically apply the correct settings (type: module in package.json, module: esnext in tsconfig.ts) if not already properly given.
Hello!
By default, tsc --init generates config for CJS. CJS code working normal out-of-the-box.

If you need to change between CJS/ESM - try:
For ESM
-
"type": "module"inpackage.json -
"module": "ES2020"intsconfig.json -
ts-node-esminstead ofts-node(or"ts-node": { "esm": true }intsconfig.json)
For CommonJS
- remove
"type": "module"frompackage.json -
"module": "commonjs"intsconfig.json -
ts-nodeinstead ofts-node-esm(or REMOVE"ts-node": { "esm": true }intsconfig.json)
Thanks @SeryiBaran but nobody is asking for instructions on how to use ESM. This is a feature request to use sensible defaults automatically to run TS files (including using ESM).
I wholeheartedly agree. Why do I need to set up a tsconfig.json file every time I just want to run a completely normal TypeScript script?
This project is way too awesome to have such a learning curve.
By normal, in the year 2023, I mean:
- top-level await
- imports locally installed packages
- imports other typescript files using relative paths (parent- or subdirectories)
- uses ESM imports and no requires
For example: I have a Next.js project that has a database folder which holds migrations. To execute a script to run the migrations, I expect just to do
npx ts-node ./src/backend/db/migrate/index.ts
and it should run.
The hoops you have to jump through if you haven't yet used ts-node:
- The
importsyntax errorimport { migrate } from 'drizzle-orm/planetscale-serverless/migrator'; ^^^^^^ SyntaxError: Cannot use import statement outside a module - You google and you find that you have to add
"type": "module"to your package.json. - Now you get
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" - Alright, let's google that -> You add
--esmas an option. - You get
CustomError: Cannot find module '/pathtorepo/src/backend/db/db'because you imported thedb.tsfile likeimport { db } from '../db';. - You try
from '../db.ts'- it doesn't work. TS says you need to use.js. - You can finally run your script. But wait. It fails because of environment variables.
- So after another googling session, you realize that importing it is probably not working, and the docs say you need to add
-r dotenv/configto the command. - Yay, your script finally runs! 🎉
...
BUT wait - now your eslint config cannot be read any more because you added
"type": "module"to yourpackage.json - You remove it, google some more, and you eventually end up having to adjust your tsconfig:
"ts-node": { "moduleTypes": { "./src/backend/db": "esm", } },
This all, to run a simple TypeScript script.
Ah, and you still have the file extension .js in your file import ... from '../db.js';