Skip to content

Hands‑On Exercise: Add TypeScript to a Small Node Project

In this exercise, you’ll take a tiny Node.js project written in plain JavaScript and convert it to TypeScript. You’ll see how TypeScript improves safety, tooling, and maintainability—without changing how the code runs.


Step 1 — Start With a Plain Node Project

Create a new folder:

mkdir node-ts-demo
cd node-ts-demo
npm init -y

Create a simple JavaScript file:

index.js

const fs = require("fs")
const path = require("path")

function loadConfig() {
  const filePath = path.join(__dirname, "config.json")
  const raw = fs.readFileSync(filePath, "utf8")
  return JSON.parse(raw)
}

const config = loadConfig()
console.log("Config loaded:", config)

Create a config file:

config.json

{
  "version": "1.0.0",
  "debug": true
}

Run it:

node index.js

Everything works—but there are no types, no autocomplete, and no safety.


Step 2 — Install TypeScript

Install TypeScript and Node types:

npm install --save-dev typescript @types/node

Initialize a TypeScript config:

npx tsc --init

This creates a tsconfig.json.


Step 3 — Configure TypeScript for Node

Open tsconfig.json and update the essentials:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "CommonJS",
    "rootDir": "./src",
    "outDir": "./dist",
    "strict": true,
    "esModuleInterop": true
  },
  "include": ["src"]
}

Create the source folder:

mkdir src

Move your JS file:

index.js → src/index.js

Step 4 — Convert the File to TypeScript

Rename:

src/index.js → src/index.ts

Now TypeScript will start analyzing it.


Step 5 — Add Types to Node Imports

Replace CommonJS with ES modules:

import fs from "fs"
import path from "path"

TypeScript automatically knows the types because of @types/node.


Step 6 — Type the loadConfig Function

Right now, TypeScript infers any for JSON.parse.

Let’s fix that.

Define a config type

type AppConfig = {
  version: string
  debug: boolean
}

Type the function

function loadConfig(): AppConfig {
  const filePath = path.join(__dirname, "config.json")
  const raw = fs.readFileSync(filePath, "utf8")
  return JSON.parse(raw) as AppConfig
}

Now TypeScript knows:

  • config.version is a string
  • config.debug is a boolean
  • accessing a missing field is an error

Let’s make the function safer:

function loadConfig(): AppConfig {
  const filePath = path.join(__dirname, "config.json")

  if (!fs.existsSync(filePath)) {
    throw new Error("Config file not found")
  }

  const raw = fs.readFileSync(filePath, "utf8")
  const parsed = JSON.parse(raw)

  return parsed as AppConfig
}

TypeScript ensures:

  • existsSync returns a boolean
  • readFileSync returns a string
  • parsed must match AppConfig

Step 8 — Compile and Run

Compile:

npx tsc

Run the output:

node dist/index.js

You now have a fully typed Node project.


Step 9 — Add a Second File (Optional)

Create a helper:

src/logger.ts

export function log(message: string): void {
  console.log(`[LOG] ${message}`)
}

Use it in index.ts:

import { log } from "./logger"

log(`Loaded version ${config.version}`)

TypeScript ensures:

  • log receives a string
  • config.version is typed
  • imports are validated

Step 10 — Observe TypeScript’s Benefits

Try breaking things:

config.version = 123 // ❌ Error
log(42)              // ❌ Error
fs.readFileSync(10)  // ❌ Error

TypeScript catches all of these before runtime.


What You Learned

This hands‑on exercise shows how TypeScript improves a Node project:

1. TypeScript integrates seamlessly with Node

  • fs, path, http, etc. have built‑in types
  • @types/node provides full coverage

2. TypeScript makes JSON parsing safer

  • define a type
  • cast the parsed result
  • catch mismatches early

3. TypeScript improves project structure

  • src → TypeScript source
  • dist → compiled JavaScript

4. TypeScript prevents common Node bugs

  • wrong argument types
  • missing files
  • incorrect return values
  • unsafe JSON parsing

This is exactly how real teams migrate JavaScript Node projects to TypeScript—incrementally, safely, and with immediate benefits.