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:
- Checks types - Reports any type errors
- Removes type annotations - JavaScript does not understand them
- 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
Option 2: Using ts-node (Recommended for Development)
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
- Create a file
src/greeting.tswith a function that takes a name and returns a greeting - Compile it using
tsc - 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
- Start TypeScript in watch mode
- Create a new file with a deliberate type error
- Observe the error in the terminal
- 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 emitbuild:clean- Delete dist folder then compiledev: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:
- The file was compiled (
dist/folder exists) - You are running the
.jsfile, not.ts - 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
- TypeScript must be compiled to JavaScript before running
- Use
tscto compile TypeScript files - Watch mode (
tsc -w) automatically recompiles on changes - ts-node runs TypeScript directly for development
- Error messages show file, line, and description - read them carefully
- noEmitOnError prevents output when there are type errors
- 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!