CLI Tool with TypeScript
In this page:
Core Concept
A typed CLI tool benefits from TypeScript by making its argument parsing and command structure type-safe, so a typo in an option name or a wrong flag type is caught before the tool ships, not when a user hits it.
Example: Core Concept
interface Options {
port: number;
verbose: boolean;
}
function parseArgs(args: string[]): Options {
return { port: 3000, verbose: args.includes("--verbose") };
}
console.log(parseArgs(["--verbose"]));
Basic Setup
A basic setup uses a library like commander or yargs (both ship TypeScript types) to define commands and options, compiling the .ts source to a runnable Node script via tsc.
Example: Basic Setup
// npm install commander
// import { program } from "commander";
console.log("commander/yargs ship TypeScript types for CLI parsing");
Typed Example
A typed example: program.option('-p, --port <number>', 'port number', Number) combined with yargs's inferred Arguments type means argv.port is known to be a number everywhere it's used, not a raw string that needs manual parsing.
Example: Typed Example
// program.option('-p, --port <number>', 'port number', Number);
interface Argv {
port: number;
}
const argv: Argv = { port: 8080 };
console.log(argv.port); // known to be a number, not a raw string
Project Usage
In a real project, a CLI's typed command handlers stay maintainable as more commands and flags get added over time, since the compiler catches a handler that forgot to account for a newly-added required option.
Example: Project Usage
interface Command {
name: string;
run: (args: string[]) => void;
}
const commands: Command[] = [
{ name: "build", run: () => console.log("Building...") },
];
commands[0].run([]);
Best Practices
Add a bin field to package.json pointing at your compiled entry file (with a #!/usr/bin/env node shebang) so the tool can be installed globally and run as a real command once built.
Example: Best Practices
// package.json: { "bin": { "mytool": "./dist/cli.js" } }
// dist/cli.js starts with: #!/usr/bin/env node
console.log("bin field + shebang lets the tool run as a global command");
Chapter Quiz — Complete all 14 topics to unlock
0/14 topics done
Complete these topics first:
- Todo App with TypeScript
- REST API with Express + TypeScript
- React Dashboard with TypeScript
- CLI Tool with TypeScript
- Library with TypeScript
- Full Stack TypeScript App
- TypeScript Design System
- TypeScript Monorepo Project
- Authentication System
- Real-time App with Socket.io
- GraphQL API with TypeScript
- Microservices with TypeScript
- TypeScript Best Practices Review
- What to Learn Next