TypeScript, for people who already write JavaScript.
Eighteen lessons on the type layer and nothing else. No JavaScript revision, no framework, no build tooling you did not ask for — just the part that is genuinely new, taught against the real compiler.
- 18 lessons
- 5h 12m of reading
- Every sample checked by the compiler
- No install, works offline
What you are getting
You know how to write JavaScript. That means roughly two thirds of the usual TypeScript tutorial is wasted on you, and the third that matters — describing the shape of data before it exists — tends to get four paragraphs. This course inverts that.
// A shape, described once.
interface Order {
id: string;
customer: { name: string; email?: string };
lines: readonly { sku: string; quantity: number }[];
placedAt: Date;
}
// A function whose contract is written down rather than remembered.
function summarise(order: Order): string {
const units = order.lines.reduce((total, line) => total + line.quantity, 0);
const contact = order.customer.email ?? 'no email on file';
const day = order.placedAt.toISOString().slice(0, 10);
return `${order.id}: ${units} units for ${order.customer.name} (${contact}) on ${day}`;
}
const order: Order = {
id: 'A-1001',
customer: { name: 'Ada' },
lines: [
{ sku: 'desk', quantity: 1 },
{ sku: 'chair', quantity: 4 },
],
placedAt: new Date('2026-01-15T09:30:00Z'),
};
console.log(summarise(order));
// Every one of these is now a compile error rather than a 3am incident:
//
// order.custmer.name misspelled property TS2551
// order.placedAt.slice(0, 10) Date has no slice TS2339
// order.customer.email.trim() might not be there TS18048
// order.lines.push({ ... }) lines is readonly TS2339
// summarise({ id: 'A-2' }) missing properties TS2345
//
// Open "What this compiles to" below. Not one of those checks costs you a
// single line at run time, because none of the types are there any more.
What this compiles to
// A function whose contract is written down rather than remembered.
function summarise(order) {
const units = order.lines.reduce((total, line) => total + line.quantity, 0);
const contact = order.customer.email ?? 'no email on file';
const day = order.placedAt.toISOString().slice(0, 10);
return `${order.id}: ${units} units for ${order.customer.name} (${contact}) on ${day}`;
}
const order = {
id: 'A-1001',
customer: { name: 'Ada' },
lines: [
{ sku: 'desk', quantity: 1 },
{ sku: 'chair', quantity: 4 },
],
placedAt: new Date('2026-01-15T09:30:00Z'),
};
console.log(summarise(order));
// Every one of these is now a compile error rather than a 3am incident:
//
// order.custmer.name misspelled property TS2551
// order.placedAt.slice(0, 10) Date has no slice TS2339
// order.customer.email.trim() might not be there TS18048
// order.lines.push({ ... }) lines is readonly TS2339
// summarise({ id: 'A-2' }) missing properties TS2345
//
// Open "What this compiles to" below. Not one of those checks costs you a
// single line at run time, because none of the types are there any more.
Output
Part one — The type layer
What TypeScript is, and the four ideas that cover most day-to-day code. Read these in order.
- 01 What TypeScript Actually Is Explain what survives compilation and what vanishes, and why that matters. 14 min
- 02 Inference, and When to Annotate Let inference do the work, and annotate only where it pays. 15 min
- 03 Objects, Interfaces and Structural Typing Describe any object shape, and explain why a name never has to match. 18 min
- 04 Unions and Literal Types Model a value that can be one of several things, precisely. 17 min
- 05 Narrowing Take a union apart safely, and know which checks the compiler trusts. 18 min
- 06 Functions Type any function, including callbacks and optional parameters. 17 min
Part two — Making it hold
Absence, generics and classes. This is where the checking starts paying for itself.
- 07 Arrays, Tuples and readonly Type arrays and tuples, and use readonly where it helps. 15 min
- 08 The Absence of a Value Handle missing values deliberately instead of hoping. 18 min
- 09 Generics Write a function or class that works over any type, and keep the types connected. 20 min
- 10 Constraints, keyof and Lookups Constrain a generic, and derive one type from another. 18 min
-
11
Classes
Type a class hierarchy, and choose between
privateand#. 19 min -
12
any, unknown and never
Reach for
unknowninstead ofany, and readnevercorrectly. 16 min
Part three — Real projects
Declarations, derived types, configuration, and moving an existing codebase across.
- 13 Type Predicates and Assertions Write a type guard, and know when you are lying to the compiler. 17 min
-
14
Enums, and What to Use Instead
Model a fixed set of values without reaching for
enum. 15 min - 15 Modules and Declaration Files Split types across files and describe an untyped library. 17 min
- 16 The Utility Types Derive the type you need from one you already have. 18 min
- 17 Mapped and Conditional Types Read a mapped or conditional type without flinching, and write a simple one. 21 min
- 18 tsconfig, and Moving JavaScript Across Configure a project deliberately and migrate JavaScript incrementally. 19 min
Nothing marked done yet. Lesson 01 is a good place to start.
How this course is different from the last two
The OOP and algorithms courses could run every sample in your browser directly, because browsers run JavaScript. Browsers do not run TypeScript, and shipping a compiler to this page would mean several megabytes of download for a course that promises to work offline.
So the arrangement here is different, and better. Every sample is compiled by the real TypeScript compiler when this site is built. What you press Run on is the JavaScript that compiler produced from the exact source you are reading. And because the compiler is involved at build time, the course can do something the other two could not:
Errors are real
A panel marked with an error code in its corner does not compile, and the message underneath it is the compiler's own words, captured during the build. If the compiler ever changed its mind, this site would fail to build until the page was corrected.
81 such panels, across 36 distinct error codes
Claims are checked
Every lesson declares which error code each counter-example should produce. The build compares that against reality and stops if they disagree. That mechanism caught fifteen mistakes in my own writing, several of which were confidently wrong.
See the README for the list
Erasure is visible
Twenty panels carry a “what this compiles to” disclosure containing the real emitted JavaScript. Nothing explains that types vanish as convincingly as watching them be absent from the output.
Try the panel above
Editing has a caveat
The one honest loss. There is no compiler in your browser, so an edited panel runs as plain JavaScript — annotations become syntax errors. The playground teaches the local workflow instead, which is what you would actually use.
playground.html
How to work through it
The order matters in one place. Lessons 03 to 05 are a single argument — shapes, then unions, then how the compiler reads your if statements — and unions feel arbitrary until narrowing explains them. Read those three together.
- Read with this page in one window and a
scratch.tsfile in the other. Every lesson ends with exercises meant for that file. - Run the panels. When a counter-example surprises you, read the compiler's message rather than my prose about it — the message is the primary source.
- Keep
npx tsc --noEmit scratch.tsin a terminal. Your editor is doing the same thing continuously, but running it yourself once makes the relationship obvious. - Skip lesson 17 on a first pass if you want to. It is the deep end and it says so.
What this does not cover
React, Vue, Node APIs, bundler configuration, decorators, and the details of publishing a typed package. Those are all worth learning and none of them are TypeScript — they are things you use TypeScript with. Lesson 18 covers enough configuration to set up a real project and stops there.
There is also no coverage of JavaScript itself. If this, prototypes, closures or async are shaky, the OOP course is the better starting point, because TypeScript will not make an unfamiliar language clearer.
Everything else
The compiler messages you will actually hit, what each one really means, and the fix. Every code here was produced by the compiler, not remembered.
DSA, typedThe templates from the algorithms course with types added: a generic heap, union-find, and a tree that will not compile until you handle the empty case.
OOP, typedThe patterns from the OOP course, now checkable. Interfaces, abstract classes, and the two kinds of private.
tsconfig referenceEvery flag worth knowing, what it costs you, and the settings this course is taught under.
PlaygroundThe local workflow: real files, `node file.ts`, and `tsc --noEmit`. Plus starters you can copy out.
GlossaryEvery term in the course in plain language, cross-referenced to its lesson.
What this is, honestly
A course written to be read offline. No account, no backend, no analytics, no network request of any kind at read time: the fonts are inlined into the stylesheet and the syntax highlighter is a few hundred lines in assets/js/highlight.js. Your progress and anything you type into a panel live in this browser's localStorage under the ts. prefix and nowhere else.
The one dependency is at build time. Producing this site requires the TypeScript compiler, because checking the samples honestly is the entire point. Reading it requires nothing.