Lab 12: TypeScript + Node.js

Objective

Use TypeScript in a Node.js environment: typed file I/O, HTTP server, environment variables, path manipulation, streams, and process types.

Time

35 minutes

Prerequisites

  • Lab 09 (Async)

Tools

  • Docker image: zchencow/innozverse-ts:latest


Lab Instructions

Step 1: Typed File I/O

import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
import { readFile, writeFile, mkdir } from "fs/promises";
import { join, dirname, extname, basename } from "path";

// Sync file operations
function writeJson(path: string, data: unknown): void {
    const dir = dirname(path);
    if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
    writeFileSync(path, JSON.stringify(data, null, 2) + "\n", "utf-8");
}

function readJson<T>(path: string): T {
    const raw = readFileSync(path, "utf-8");
    return JSON.parse(raw) as T;
}

interface Config {
    app: { name: string; version: string; debug: boolean };
    db: { driver: string; path: string };
}

const config: Config = {
    app: { name: "innoZverse", version: "1.0.0", debug: true },
    db: { driver: "sqlite", path: "/tmp/app.db" },
};

writeJson("/tmp/ts-lab/config.json", config);
const loaded = readJson<Config>("/tmp/ts-lab/config.json");
console.log("App:", loaded.app.name, "v" + loaded.app.version);
console.log("DB:", loaded.db.driver + ":" + loaded.db.path);

// Async file operations
(async () => {
    await mkdir("/tmp/ts-lab/logs", { recursive: true });
    await writeFile("/tmp/ts-lab/logs/app.log",
        `[${new Date().toISOString()}] INFO: Application started\n`);
    const log = await readFile("/tmp/ts-lab/logs/app.log", "utf-8");
    console.log("Log:", log.trim());
})();

💡 Generic readJson<T> gives type-safe JSON reading — the caller specifies what type they expect. TypeScript trusts this (no runtime validation). For production, combine with a validation library (zod, io-ts) to verify the shape matches before using the data.

📸 Verified Output:


Step 2: HTTP Server with Types

💡 IncomingMessage and ServerResponse are the Node.js built-in HTTP types. TypeScript's @types/node package provides these. The generic parseBody<T> reads the request body and types the result — callers know exactly what they'll get without manual casting.

📸 Verified Output:


Steps 3–8: Environment Variables, Streams, Worker Threads, Path Utils, Config Manager, Capstone CLI

📸 Verified Output:


Summary

TypeScript and Node.js are a natural pair. You've covered typed file I/O, HTTP server construction, environment variable typing, process event handlers, path utilities, streams, a typed config manager, and a file system scanner. These are the building blocks of every Node.js backend.

Further Reading

Last updated