Command Line Subcommands in TypeScript

Here’s the translation of the Go code to TypeScript, along with explanations in Markdown format suitable for Hugo:

Command-line tools often have subcommands, each with its own set of flags. For example, git clone and git push are two different subcommands of the git tool. In TypeScript, we can use libraries like commander or yargs to easily define subcommands with their own flags.

import { Command } from 'commander';

const program = new Command();

// We declare a subcommand using the .command() method,
// and proceed to define new options specific for this subcommand.
const fooCommand = program.command('foo')
    .option('-e, --enable', 'enable')
    .option('-n, --name <name>', 'name')
    .action((options, command) => {
        console.log("subcommand 'foo'");
        console.log("  enable:", options.enable || false);
        console.log("  name:", options.name || '');
        console.log("  args:", command.args);
    });

// For a different subcommand we can define different supported options.
const barCommand = program.command('bar')
    .option('-l, --level <level>', 'level', '0')
    .action((options, command) => {
        console.log("subcommand 'bar'");
        console.log("  level:", options.level);
        console.log("  args:", command.args);
    });

// Parse the command line arguments
program.parse(process.argv);

// If no subcommand is provided, show help
if (!process.argv.slice(2).length) {
    program.outputHelp();
}

To run the program:

$ ts-node command-line-subcommands.ts foo -e -n=joe a1 a2
subcommand 'foo'
  enable: true
  name: joe
  args: [ 'a1', 'a2' ]

$ ts-node command-line-subcommands.ts bar -l 8 a1
subcommand 'bar'
  level: 8
  args: [ 'a1' ]

But bar won’t accept foo’s options:

$ ts-node command-line-subcommands.ts bar -e a1
error: unknown option '-e'

In this TypeScript version, we’re using the commander library to handle command-line parsing. This library provides a more idiomatic way to define subcommands and their options in TypeScript/JavaScript.

The structure is similar to the original example:

  1. We define subcommands using program.command().
  2. For each subcommand, we define options using the option() method.
  3. We provide an action for each subcommand that will be executed when that subcommand is invoked.
  4. The program automatically parses the command-line arguments and routes them to the appropriate subcommand.

This approach provides a clean and extensible way to create command-line tools with subcommands in TypeScript.

Next, we’ll look at environment variables, another common way to parameterize programs.