01 — annotations
Types that check, then erase — the ecosystem is untouched.
function tally(xs: number[]): number {
return xs.reduce((a, b) => a + b, 0);
}
tally("123"); // error, at compile time← the guideMulticore & Missions
§ 02 — Eras · 2012
JavaScript with a contract
Left: era context, features, and the 101 hello. Right: 3 core concepts, 3 deeper 201 lessons, the factorial specimen, and where TypeScript lives today — each column scrolls on its own.
JavaScript at scale had no safety net. TypeScript added types that check — then erase — without leaving the ecosystem.
The types vanish at runtime; any is a trapdoor; and you maintain two languages in your head forever.
Session one is the smallest program that still counts as speaking TypeScript: what every tutorial prints first, in the dialect that mattered when the language arrived (2012).
const greet = (name: string): string =>
`Hello, ${name}`;
console.log(greet("world"));101First contact — hello world and 3 ideas that define how TypeScript reads. 201 — 3 lessons on mechanisms you meet after the factorial specimen: the sharp edges practitioners actually use.
3 fragments, each naming a habit of mind in TypeScript. Read the note, then the code — together they are the 101 in one sitting.
01 — annotations
Types that check, then erase — the ecosystem is untouched.
function tally(xs: number[]): number {
return xs.reduce((a, b) => a + b, 0);
}
tally("123"); // error, at compile time02 — interfaces
Structural typing: shape matters, declarations don’t.
interface Ship {
name: string
tons: number
}
const s: Ship = { name: "Perch", tons: 24 };03 — narrowing
Unions plus control-flow analysis — invalid states become unrepresentable.
function desc(x: string | number): string {
return typeof x === "number"
? `tons: ${x}`
: x.toUpperCase();
}The 201 assumes you have read the 101 and the specimen. Each lesson is one mechanism — what it is for, how it looks in code, and the trap or payoff that makes TypeScript distinctive at scale.
Constraints describe what a type parameter must provide; without them TypeScript falls back to any, which erases the safety you came for.
function tally<T extends number>(xs: T[]): T {
return xs.reduce((a, b) => (a + b) as T, 0 as T);
}Types can branch on other types: mapped types rewrite a shape, template literal types build strings, and conditional types pick a type from another type.
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]
}typeof, in, instanceof and user-defined type predicates all narrow a union — the compiler’s answer to runtime checks.
function isShip(x: unknown): x is Ship {
return typeof x === "object" && x !== null && "tons" in x;
}The gradual type: types that check, not obstruct — JavaScript with a contract, adopted by the mainstream without rewriting the world.
function tally(xs: number[]): number {
return xs.reduce((a, b) => a + b, 0);
}
tally("123"); // error: not assignablerunbunx tsx fact.ts
Every major frontend codebase and a fast-growing share of backends; the types vanish at runtime.