Your First TypeScript Program
TypeScript is JavaScript with a type layer on top. Before your code runs in the browser
or Node.js, the TypeScript compiler (tsc) reads your .ts files, checks that all the
types are consistent, and emits plain .js files. This page walks you through that
entire cycle — create, compile, inspect, run — step by step.
Prerequisites
You need Node.js and npm installed. TypeScript is installed as a development dependency or globally via npm.
Node.js 18 or later (https://nodejs.org)
npm (bundled with Node.js)
A terminal / command prompt
A text editor (VS Code works great — it has TypeScript support built in)
Step 1 — Install TypeScript
Create a new folder for this project, then install TypeScript locally:
mkdir hello-ts cd hello-ts npm init -y npm install --save-dev typescript
After installation, the TypeScript compiler lives at node_modules/.bin/tsc. You can
run it directly, or use npx tsc to have npm find it for you.
npx tsc --version
Version 5.5.4
Step 2 — Create hello.ts
Create a file called hello.ts in your project folder and add this code:
// hello.ts
function greet(name: string): string {
return `Hello, ${name}! Welcome to TypeScript.`;
}
const message: string = greet('World');
console.log(message);Take a moment to notice the type annotations:
name: string— the parameternamemust be a string: stringafter the parentheses — the function must return a stringconst message: string— the variable holds a string
These annotations do not change what the code does at runtime. They are instructions
to the TypeScript compiler about what types are expected. If you violate them, tsc
will refuse to compile.
Step 3 — Compile with tsc
Run the compiler, pointing it at your source file:
npx tsc hello.ts
If everything is correct, the compiler exits silently and creates hello.js in the
same folder. No output means success — that is the Unix convention.
Step 4 — Inspect the Generated .js
Open hello.js. Here is what TypeScript emitted:
// hello.js (generated by tsc)
function greet(name) {
return `Hello, ${name}! Welcome to TypeScript.`;
}
var message = greet('World');
console.log(message);Notice what changed and what did not:
- Type annotations are gone.
name: stringbecame justname. JavaScript engines do not understand TypeScript syntax, sotscstrips all the types before emitting. - The template literal survived. TypeScript targets ES3 by default for maximum
compatibility. In newer targets (
--target ES2015or later) template literals are kept as-is. constbecamevarwhen targeting ES3/ES5. Use--target ES2020to keepconstandlet.
.js file, TypeScript is out of the picture.Step 5 — Run with Node
Execute the compiled file with Node.js:
node hello.js
Hello, World! Welcome to TypeScript.
The compile-run cycle in full:
npx tsc hello.ts && node hello.js
The Compile-Run Mental Model
Understanding this two-step model is the key insight for new TypeScript developers:
You write .ts source files with type annotations
tsc reads the .ts files, checks types, and emits .js files
Node.js (or the browser) executes the .js files — it never sees the .ts
Type errors stop compilation; runtime errors happen later when the .js runs
This means TypeScript catches an entire class of bugs before you ever run the program. But it cannot catch every bug — only type-level mistakes. Logic errors still show up at runtime.
Introducing a Deliberate Type Error
Let's break the code on purpose to see what the compiler does. Change the greet call
to pass a number instead of a string:
// hello.ts — broken version
function greet(name: string): string {
return `Hello, ${name}! Welcome to TypeScript.`;
}
const message: string = greet(42); // ← pass a number
console.log(message);npx tsc hello.ts
hello.ts:7:30 - error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.
7 const message: string = greet(42); // ← pass a number
~~
Found 1 error in hello.ts:7Read this error from top to bottom:
hello.ts:7:30— the error is inhello.ts, line 7, column 30- TS2345 — the TypeScript error code (useful for searching the docs)
- Argument of type 'number' is not assignable to parameter of type 'string' — plain English description of the problem
- The squiggly underline points exactly at
42
42 to "42" in many contexts.Wrong Return Type
Here is another type error — returning the wrong type from a function:
function greet(name: string): string {
return 42; // ← number, but function is declared to return string
}hello.ts:2:10 - error TS2322: Type 'number' is not assignable to type 'string'.
2 return 42;
~~Type Annotations on Variables
You can annotate variables directly, though TypeScript can usually infer the type from the initial value:
// Explicit annotation const name: string = 'Alice'; const age: number = 30; const active: boolean = true; // Inferred — same result, less typing const name2 = 'Alice'; // TypeScript infers: string const age2 = 30; // TypeScript infers: number const active2 = true; // TypeScript infers: boolean // Annotation required when the type can't be inferred let score: number; // no initial value → must annotate score = 100;
String Interpolation in TypeScript
TypeScript supports the same template literals as modern JavaScript. The types make them more useful because the compiler knows what you are interpolating:
function formatUser(name: string, age: number): string {
return `${name} is ${age} years old.`;
}
console.log(formatUser('Alice', 30));
// → Alice is 30 years old.
// The compiler knows age is a number, so this is fine:
console.log(`Next year: ${age + 1}`); // TS knows age is number
// But this would be a type error if age were typed as string:
// const badAge: string = '30';
// console.log(badAge + 1); // string + number = "301" in JS — not what you wanthello.ts vs hello.js — Side by Side
Here is the same greeting program shown side by side as TypeScript source and the emitted JavaScript (targeting ES2020):
// hello.ts (TypeScript source)
function greet(name: string, times: number = 1): string {
const lines: string[] = [];
for (let i: number = 0; i < times; i++) {
lines.push(`[${i + 1}] Hello, ${name}!`);
}
return lines.join('\n');
}
const output: string = greet('World', 3);
console.log(output);// hello.js (emitted by tsc --target ES2020)
function greet(name, times = 1) {
const lines = [];
for (let i = 0; i < times; i++) {
lines.push(`[${i + 1}] Hello, ${name}!`);
}
return lines.join('\n');
}
const output = greet('World', 3);
console.log(output);[1] Hello, World! [2] Hello, World! [3] Hello, World!
The emitted JavaScript is clean, readable, and equivalent to what you would write by hand. TypeScript adds zero runtime overhead — the type annotations simply disappear.
Workflow Summary
Write your logic in .ts files with type annotations
Run npx tsc to compile — fix any errors it reports
Run the emitted .js files with node or deploy them to a browser
During development, use tsc --watch to recompile on every save
# One-time compile npx tsc hello.ts # Watch mode — recompiles whenever the file changes npx tsc hello.ts --watch
.ts source — never hand-edit the generated.js files. Your changes will be overwritten the next timetsc runs.Quick Reference
hello.ts → source file you edit
npx tsc hello.ts → compiles to hello.js
node hello.js → executes the compiled output
Type annotations use the colon syntax: name: string
Return type goes after the closing parenthesis: ): string
Type errors block compilation — fix them before running
tsc --watch recompiles automatically on save