Project: Type-Safe CLI Todo Tool

Introduction

This project builds a command-line todo app in TypeScript: typed models, parsed commands, JSON file persistence, and clear error messages. You practice Node + tsc (or tsx) workflows from the integration chapters in one small tool you can extend later.

Prerequisites

Project Goals

  • Define Todo and status types
  • Parse subcommands: add, list, done, remove
  • Persist todos in todos.json
  • Exit with non-zero code on user errors

Folder Setup

bash
mkdir ts-todo-cli
cd ts-todo-cli
npm init -y
npm install --save-dev typescript @types/node tsx
text
ts-todo-cli/
├── package.json
├── tsconfig.json
└── src/
    ├── index.ts
    ├── types.ts
    ├── store.ts
    └── commands.ts

tsconfig.json:

json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "outDir": "dist",
    "rootDir": "src",
    "strict": true
  },
  "include": ["src/**/*"]
}

package.json scripts:

json
{
  "type": "module",
  "bin": { "todos": "./dist/index.js" },
  "scripts": {
    "build": "tsc",
    "dev": "tsx src/index.ts",
    "start": "node dist/index.js"
  }
}

Step 1: Domain Types

src/types.ts:

Code explanation:

  • TodoStatus is a string union—invalid statuses fail at compile time
  • Command is a discriminated union keyed by name

Step 2: File Store

src/store.ts:

Step 3: Commands

src/commands.ts:

Step 4: CLI Entry

src/index.ts:

Try It

bash
npm run dev -- add "Learn TypeScript"
npm run dev -- list
npm run dev -- done <id-from-list>
npm run build
npm start -- list

Extensions (Optional)

  • Add edit command with Partial<Pick<Todo, "title" | "status">>
  • Validate duplicate titles
  • Publish to npm with bin field and files: ["dist"]

FAQ

Why validate JSON with isTodo?

Runtime data from disk is untrusted even on your machine.

Use a CLI library?

commander or yargs add typed options—good next step after manual parsing.

Zod for parsing?

Popular for runtime schemas—pairs well with unknown at boundaries.