From Zero to AI

Lesson 2.4: Compilation and Running

Duration: 55 minutes

Learning Objectives

By the end of this lesson, you will be able to:

  • Compile TypeScript files to JavaScript using tsc
  • Understand what happens during compilation
  • Run compiled JavaScript with Node.js
  • Use watch mode for automatic recompilation
  • Debug compilation errors

Why Compilation?

TypeScript cannot run directly. Browsers and Node.js only understand JavaScript. The TypeScript compiler (tsc) converts your .ts files into .js files.

┌─────────────┐     ┌───────────┐     ┌─────────────┐
│  index.ts   │ --> │    tsc    │ --> │  index.js   │
│ (TypeScript)│     │ (Compiler)│     │ (JavaScript)│
└─────────────┘     └───────────┘     └─────────────┘
                                            │
                                            v
                                      ┌───────────┐
                                      │  Node.js  │
                                      │  Browser  │
                                      └───────────┘

During compilation, TypeScript:

  1. Checks types - Reports any type errors
  2. Removes type annotations - JavaScript does not understand them
  3. Transforms modern syntax - Converts to target JavaScript version

Basic Compilation

Compiling a Single File

# Compile a single TypeScript file
tsc src/index.ts

This creates src/index.js in the same directory.

Compiling with tsconfig.json

When you have a tsconfig.json, just run:

tsc

This compiles all files according to your configuration.

Example: Before and After

Before (TypeScript - index.ts):

const greet = (name: string): string => {
  return `Hello, ${name}!`;
};

const message: string = greet('World');
console.log(message);

After (JavaScript - index.js):

'use strict';
const greet = (name) => {
  return `Hello, ${name}!`;
};
const message = greet('World');
console.log(message);

Notice:

  • Type annotations (: string) are removed
  • The logic remains the same
  • "use strict" is added automatically

Running Compiled Code

After compilation, run the JavaScript with Node.js:

# Compile
tsc

# Run
node dist/index.js

Combined Command

You can chain commands:

tsc && node dist/index.js

Or add an npm script in package.json:

{
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js",
    "build:start": "tsc && node dist/index.js"
  }
}

Then run:

npm run build:start

Watch Mode

Manually running tsc every time you make changes is tedious. Watch mode automatically recompiles when files change.

Enable Watch Mode

tsc --watch

Or with the shorthand:

tsc -w

What Happens in Watch Mode

[10:30:15] Starting compilation in watch mode...
[10:30:16] Found 0 errors. Watching for file changes.

# You edit index.ts...

[10:30:45] File change detected. Starting incremental compilation...
[10:30:45] Found 0 errors. Watching for file changes.

TypeScript watches your files and recompiles instantly when you save.

npm Script for Watch

{
  "scripts": {
    "dev": "tsc --watch"
  }
}

Run with:

npm run dev

Understanding the Output

Output Directory Structure

With this tsconfig.json:

{
  "compilerOptions": {
    "rootDir": "./src",
    "outDir": "./dist"
  }
}

Your project structure changes like this:

Before compilation:

project/
├── src/
│   ├── index.ts
│   └── utils/
│       └── helpers.ts
└── tsconfig.json

After compilation:

project/
├── src/
│   ├── index.ts
│   └── utils/
│       └── helpers.ts
├── dist/
│   ├── index.js
│   └── utils/
│       └── helpers.js
└── tsconfig.json

The directory structure in src/ is mirrored in dist/.

Source Maps

If you enable source maps:

{
  "compilerOptions": {
    "sourceMap": true
  }
}

You get .js.map files:

dist/
├── index.js
├── index.js.map
└── utils/
    ├── helpers.js
    └── helpers.js.map

Source maps let debuggers show TypeScript code even though JavaScript runs.


Handling Compilation Errors

When TypeScript finds errors, it reports them and (by default) still outputs JavaScript.

Example Error

// src/index.ts
const add = (a: number, b: number): number => {
  return a + b;
};

const result = add('5', 10); // Error!
console.log(result);

Output:

src/index.ts:5:20 - error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.

5 const result = add("5", 10);
                     ~~~

Found 1 error in src/index.ts:5

Reading Error Messages

Error format:

file:line:column - error TSXXXX: Message
  • file: Which file has the error
  • line:column: Exact location
  • TSXXXX: Error code (searchable for more info)
  • Message: What is wrong

Preventing Output on Errors

Add to tsconfig.json:

{
  "compilerOptions": {
    "noEmitOnError": true
  }
}

Now TypeScript will not create JavaScript files if there are type errors.


Useful Compiler Options

--noEmit

Type-check without generating output:

tsc --noEmit

Useful for:

  • CI/CD pipelines checking types
  • When a bundler (Webpack, Vite) handles compilation

--declaration

Generate type definition files:

tsc --declaration

Creates .d.ts files alongside .js files. Useful for libraries.

--listFiles

Show which files are being compiled:

tsc --listFiles

--pretty

Format errors with colors (default is on):

tsc --pretty

Development Workflow

Here is a typical workflow when developing with TypeScript:

Option 1: Watch Mode + Manual Run

Terminal 1:

npm run dev  # tsc --watch

Terminal 2:

node dist/index.js  # Run when needed

Install ts-node to run TypeScript directly:

npm install --save-dev ts-node

Run TypeScript files without manual compilation:

npx ts-node src/index.ts

Add to package.json:

{
  "scripts": {
    "dev": "ts-node src/index.ts"
  }
}

Option 3: Using tsx (Faster Alternative)

npm install --save-dev tsx
npx tsx src/index.ts

Or with watch mode:

npx tsx watch src/index.ts

Practical Example: Complete Workflow

Let us walk through a complete example.

Step 1: Create Project Structure

mkdir ts-example
cd ts-example
npm init -y
npm install --save-dev typescript ts-node

Step 2: Create tsconfig.json

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

Step 3: Create Source File

// src/index.ts
interface Task {
  id: number;
  title: string;
  completed: boolean;
}

const tasks: Task[] = [];

const addTask = (title: string): Task => {
  const task: Task = {
    id: tasks.length + 1,
    title: title,
    completed: false,
  };
  tasks.push(task);
  return task;
};

const completeTask = (id: number): void => {
  const task = tasks.find((t) => t.id === id);
  if (task) {
    task.completed = true;
  }
};

const listTasks = (): void => {
  console.log('\n--- Tasks ---');
  tasks.forEach((task) => {
    const status = task.completed ? '[x]' : '[ ]';
    console.log(`${status} ${task.id}. ${task.title}`);
  });
  console.log('-------------\n');
};

// Demo
addTask('Learn TypeScript basics');
addTask('Set up project');
addTask('Write first program');

listTasks();

completeTask(1);
completeTask(2);

listTasks();

Step 4: Add Scripts to package.json

{
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js",
    "dev": "ts-node src/index.ts",
    "watch": "tsc --watch"
  }
}

Step 5: Run the Program

Development (direct execution):

npm run dev

Production (compile then run):

npm run build
npm start

Expected output:

--- Tasks ---
[ ] 1. Learn TypeScript basics
[ ] 2. Set up project
[ ] 3. Write first program
-------------

--- Tasks ---
[x] 1. Learn TypeScript basics
[x] 2. Set up project
[ ] 3. Write first program
-------------

Exercises

Exercise 1: Compile and Run

  1. Create a file src/greeting.ts with a function that takes a name and returns a greeting
  2. Compile it using tsc
  3. Run the compiled JavaScript
// src/greeting.ts - write your code here
Solution
// src/greeting.ts
const createGreeting = (name: string): string => {
  return `Welcome, ${name}! Glad to have you here.`;
};

const greeting = createGreeting('TypeScript Developer');
console.log(greeting);

Commands:

tsc
node dist/greeting.js

Output:

Welcome, TypeScript Developer! Glad to have you here.

Exercise 2: Fix Compilation Errors

This code has errors. Fix them so it compiles:

const multiply = (a: number, b: number): number => {
  return a * b;
};

const result = multiply(5, "10");

const user = {
  name: "Alice"
  email: "alice@example.com"
};

console.log(user.Name);
Solution
const multiply = (a: number, b: number): number => {
  return a * b;
};

// Fix 1: Second argument should be a number
const result = multiply(5, 10);

// Fix 2: Missing comma between properties
const user = {
  name: 'Alice',
  email: 'alice@example.com',
};

// Fix 3: Property name is lowercase 'name', not 'Name'
console.log(user.name);

Exercise 3: Watch Mode Practice

  1. Start TypeScript in watch mode
  2. Create a new file with a deliberate type error
  3. Observe the error in the terminal
  4. Fix the error and observe automatic recompilation
Steps
# Terminal 1: Start watch mode
tsc --watch

# Terminal 2 or editor: Create file with error
# src/test.ts
const value: number = "hello";  # Error!

# Watch terminal shows error immediately

# Fix the error
const value: number = 42;

# Watch terminal shows successful compilation

Exercise 4: Add Development Scripts

Update your package.json with these scripts:

  • type-check - Only check types, do not emit
  • build:clean - Delete dist folder then compile
  • dev:watch - Run ts-node in watch mode (hint: use nodemon)
Solution
{
  "scripts": {
    "type-check": "tsc --noEmit",
    "build:clean": "rm -rf dist && tsc",
    "dev:watch": "nodemon --exec ts-node src/index.ts --ext ts"
  },
  "devDependencies": {
    "typescript": "^5.0.0",
    "ts-node": "^10.0.0",
    "nodemon": "^3.0.0"
  }
}

Note: Install nodemon first: npm install --save-dev nodemon


Common Issues and Solutions

Issue: "Cannot find module"

Cause: Node.js cannot find the compiled file.

Solution: Check that:

  1. The file was compiled (dist/ folder exists)
  2. You are running the .js file, not .ts
  3. The path is correct

Issue: "tsc: command not found"

Cause: TypeScript is not installed globally.

Solution:

# Option 1: Install globally
npm install -g typescript

# Option 2: Use npx
npx tsc

Issue: Compiled file is outdated

Cause: You edited the TypeScript but did not recompile.

Solution: Use watch mode or recompile:

tsc --watch  # Automatic
tsc          # Manual

Key Takeaways

  1. TypeScript must be compiled to JavaScript before running
  2. Use tsc to compile TypeScript files
  3. Watch mode (tsc -w) automatically recompiles on changes
  4. ts-node runs TypeScript directly for development
  5. Error messages show file, line, and description - read them carefully
  6. noEmitOnError prevents output when there are type errors
  7. Source maps enable debugging TypeScript code

Resources

Resource Type Description
tsc CLI Reference Documentation All compiler options
ts-node Documentation Documentation Run TypeScript directly
TypeScript Compilation Documentation How compilation works

Module Complete!

Congratulations! You have completed Module 2: Introduction to TypeScript. You now know:

  • Why TypeScript exists and its benefits
  • How to set up and configure a TypeScript project
  • How to write TypeScript code with type annotations
  • How to compile and run TypeScript programs

You are ready to dive deeper into TypeScript's type system!

Continue to Module 3: Types and Interfaces