builtbylukas.dev

From TypeScript to Terminal: How to Run Your Code Directly

I love TypeScript as a language for building web applications. But a few days ago I wondered if it was possible to run the code as if it was a shell script. Usually, I just run the code through a build step or a tool like ts-node. But it is actually possible to just run your project from the terminal, as if it was a shell script! In this article, I’m going to show how you can achieve this, using the commit-ai project (link to the project) as a case study.

Goal: A Seamless CLI Experience

The goal is to be able to run a command like commit-ai (in my case) from anywhere in your system, and have it execute your TypeScript code. This is a common requirement for CLI tools, and it’s actually surprisingly easy to set up!

The Build Step: Compiling to JavaScript

Yes, we need a build step. The first thing to understand is that Node.js doesn’t run TypeScript directly. It runs JavaScript. So, we need to compile our TypeScript code to JavaScript before we can run it. I just use the TypeScript compiler tsc:

In our package.json, you’ll need a build script that runs tsc:

"scripts": {
"build": "tsc"
}

This command will look at our tsconfig.json file to figure out how to compile the code. A typical setup is to compile the code in /src into dist/

tsconfig.json:

{
  "compilerOptions": {
    // ...
    "outDir": "./dist"
  },
  "include": [
    "src"
  ],
  "exclude": [
    "dist",
    "node_modules"
  ]
}

The bin Field: Creating a Command-Line Alias in package.json

Now that we have our compiled JavaScript, we need to tell Node.js how to run it as a command-line tool. This is where the bin field in package.json comes in handy.

"bin": {
"commit-ai": "dist/index.js"
},

This field tells npm (or pnpm, or yarn) to create a symbolic link from the command commit-ai to our compiled dist/index.js file. When you install this package globally, you’ll be able to run commit-ai from anywhere in your terminal.

The Shebang: Making the Script Executable

At the very top of your index.ts file, you’ll want to add the following line:

#!/usr/bin/env node

This is called a “shebang”. It’s a special line that tells the operating system what interpreter to use to run the script. In this case, we’re telling it to use the node interpreter.

When you run the commit-ai command, the operating system will see the shebang and know to execute the script with Node.js.

Linking the Package: Making it Global

Now that we have everything set up, the last step is to make our command available system-wide. We can do this with the pnpm link --global command (or npm link if you’re using npm).

This command will create a symbolic link from the global node_modules directory to our project directory. This means that you can now run commit-ai from any directory on your system.

Putting It All Together

So, to recap, here’s the entire process:

  1. Write your TypeScript code, making sure to include the shebang at the top of your main file.
  2. Add a build script to your package.json that runs tsc.
  3. Add a bin field to your package.json that points to your compiled JavaScript file.
  4. Run pnpm install to install your dependencies.
  5. Run pnpm build to compile your TypeScript code to JavaScript.
  6. Run pnpm link --global to make your command available system-wide.

And that’s it! You can now run your TypeScript code directly from the terminal. This is a powerful technique that can help you build professional-grade CLI tools with TypeScript.

References