ts-node icon indicating copy to clipboard operation
ts-node copied to clipboard

Suggestion: always run ".ts" files. Don't ever say .ts is unknown.

Open mikemaccana opened this issue 2 years ago • 7 comments

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.

mikemaccana avatar Mar 09 '23 14:03 mikemaccana

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.

mike-lischke avatar Mar 30 '23 13:03 mike-lischke

Hello!

By default, tsc --init generates config for CJS. CJS code working normal out-of-the-box.

cjs-work

If you need to change between CJS/ESM - try:

For ESM

  • "type": "module" in package.json
  • "module": "ES2020" in tsconfig.json
  • ts-node-esm instead of ts-node (or "ts-node": { "esm": true } in tsconfig.json)

For CommonJS

  • remove "type": "module" from package.json
  • "module": "commonjs" in tsconfig.json
  • ts-node instead of ts-node-esm (or REMOVE "ts-node": { "esm": true } in tsconfig.json)

SeryiBaran avatar Apr 10 '23 16:04 SeryiBaran

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).

mikemaccana avatar Apr 11 '23 07:04 mikemaccana

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:

  1. The import syntax error
    import { migrate } from 'drizzle-orm/planetscale-serverless/migrator';
    ^^^^^^
    
    SyntaxError: Cannot use import statement outside a module
    
  2. You google and you find that you have to add "type": "module" to your package.json.
  3. Now you get TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts"
  4. Alright, let's google that -> You add --esm as an option.
  5. You get CustomError: Cannot find module '/pathtorepo/src/backend/db/db' because you imported the db.ts file like import { db } from '../db';.
  6. You try from '../db.ts' - it doesn't work. TS says you need to use .js.
  7. You can finally run your script. But wait. It fails because of environment variables.
  8. So after another googling session, you realize that importing it is probably not working, and the docs say you need to add -r dotenv/config to the command.
  9. Yay, your script finally runs! 🎉 ... BUT wait - now your eslint config cannot be read any more because you added "type": "module" to your package.json
  10. 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';

michaelschufi avatar May 03 '23 11:05 michaelschufi