83 concrete items to go from "it compiles" to "I master the type system".
Why this book
TypeScript has a reversed reputation problem: everyone uses it, almost nobody understands it. You annotate until the red squiggles go away, you reach for an as or an any when the compiler pushes back, and you call that "doing TypeScript". The code compiles, but every type error remains a negotiation by gut feeling.
Vanderkam wrote what he himself calls a "standard second book": not a manual to get started, a book to go from user to expert. The method, inherited from Effective C++ and Effective Java: 83 short items, each one actionable rule; and he owns it from the preface: "Whereas a reference book will explain the five ways that a language lets you do X, an Effective book will tell you which of those five to use and why" (1st ed., p. xi-xii). The second edition (May 2024) adds two whole chapters, including type-level programming.
The ideas that stay
1TypeScript models JavaScript, flaws included
Why doesn't const x = 2 + '3' raise any error? Because it's valid JavaScript (result: the string "23"), and because "TypeScript's type system models the runtime behavior of JavaScript" (1st ed., p. 5). TS isn't there to fix JS, it's there to describe it. And Vanderkam drops the founding admission as early as item 1: "TypeScript's type system is very much not sound, nor was it ever intended to be. If soundness is important to you, you may want to look at other languages like Reason or Elm" (1st ed., p. 5). Accepting that trade-off explains 80% of the language's "weird" behaviors.
2A type is a set of values, everything else follows
The book's central mental model (item 7): every type is the set of values it admits. never is the empty set, a literal type "x" is a singleton, A | B is a union of sets, A & B an intersection. And the rule that defuses the most cryptic error messages: "Think of 'extends,' 'assignable to,' and 'subtype of' as synonyms for 'subset of'" (item 7). The classic paradox lights up at once: A & B intersects the values, not the properties. Fewer admissible values (each must satisfy both constraints), hence more guaranteed properties: the union of the members. Symmetrically, on A | B only the shared properties are accessible before narrowing. The book condenses it into two formulas: keyof (A&B) = (keyof A) | (keyof B) and keyof (A|B) = (keyof A) & (keyof B) (item 7). More constraints, fewer values, more guaranteed properties. Same logic: Vector3D is a subset of Vector2D (more properties = smaller domain), and the extends in generics isn't about inheritance, it's about subsets.
3Types evaporate at runtime
tsc does two independent jobs: checking types and emitting JavaScript. Independent to the point that "The types in your code cannot affect the JavaScript that TypeScript emits […] your types can't affect the way your code runs" (1st ed., p. 10). Three concrete traps follow: instanceof Rectangle fails if Rectangle is an interface (erased at compile time; you need a tagged union or a class); as number converts NOTHING at runtime; and code with type errors can still produce running JS. Anyone who has ever wondered why their as "didn't work" has paid to learn this item.
4Typing is structural, and your types are open
JavaScript is "inherently duck typed" (1st ed., p. 15) and TypeScript follows: if the object has the right properties, it passes, no matter how it was built. The book's example: a function expecting a Vector2D happily accepts a Vector3D; the z component is silently ignored. "Like it or not, your types are 'open'": there is no way to seal a type. That's not a bug, it's JavaScript's model; but it explains why Object.keys gives you string and not keyof T.
5A good type makes invalid states impossible to write
The example that sticks: the crash of Air France flight 447. The Airbus side sticks were independent and the plane averaged the two inputs; one pilot pulled, the other pushed, and the system accepted that contradictory state (1st ed., ch. 4). The book models it in TypeScript, before and after:
// ✗ Flight 447: two independent sticks, the contradictory state is representable interface CockpitControls { leftSideStick: number; // 0 = neutral, + = forward rightSideStick: number; // may say the opposite of the first… } // ✓ Mechanically linked controls: contradiction is impossible interface CockpitControls { stickAngle: number; // no getStickSetting() needed anymore }
With two fields, any getStickSetting function has to pick which stick to believe, and every strategy the book tries (trust the pilot, average the two…) fails. With one field, "our flowcharts are obvious. You don't need a getStickSetting function at all" (1st ed., ch. 4). On the web side, it's the State { isLoading: boolean; error?: string } interface that allows "loading AND failed" at the same time: the tagged union Pending | Error | Success makes the contradiction inexpressible. The official Thing to Remember: "Prefer types that only represent valid states. Even if they are longer or harder to express, they will save you time and pain in the end!" (item 29).
6any is contagious, unknown is the antidote
An any returned by a function silently contaminates every caller: no more autocompletion, no more checks on refactoring, hidden bugs. Vanderkam's verdict is cruel: "TypeScript with lots of any types can be harder to work with than untyped JavaScript" (1st ed., p. 24), because you pay the cost of types without the protection. The antidote: unknown, the "I don't know yet" type, which forces narrowing before use. The book's running example: parseYAML and the Brontë sisters' novels.
const book = parseYAML(` name: Jane Eyre author: Charlotte Brontë `); console.log(book.title); // no error, logs "undefined" at runtime book('read'); // no error, throws "book is not a function"
With unknown as the return type, both lines refuse to compile until you've proven what book is (item 46).
7Generics are functions between types (the new chapter that justifies the 2nd edition)
The brand-new chapter 6 finally gives type-level TypeScript a framework: "Think of generic types as functions between types" (item 50). MyPick<T, K> takes two types and returns a third, exactly like a function. His golden rule fits in one sentence: a type parameter must appear at least twice to establish a relationship; otherwise it relates nothing and lies (the parseYAML<T> anti-pattern that "returns" whatever type you ask for without checking anything, item 51). The chapter covers template literal types (a querySelector that understands "button#id"), recursive types, even type testing. With a guardrail rarely seen in this kind of chapter: "While type-level TypeScript is an impressively powerful tool, it's not always the best tool for the job" (item 58); past a complexity threshold, generate types from the source (codegen) instead of computing them.
8Migrating: in order, and noImplicitAny last
The final chapter is an experience report: Vanderkam migrated dygraphs, his aging charting library, and distills a battle plan. Modernize the JS first, enable allowJs, migrate module by module up the dependency graph (leaves first, tests last), resist the urge to refactor along the way, and only turn on noImplicitAny at the very end. The numbers that motivate, from the studies the chapter cites: "15% of bugs fixed in JavaScript projects on GitHub could have been prevented with TypeScript", and 38% of AirBnb's postmortems.
Three things I didn't know before reading it
- The book's sample data is the Brontë sisters' novels: Wuthering Heights (Emily), Jane Eyre (Charlotte), The Tenant of Wildfell Hall (Anne), one sister per
parseYAMLvariant (items 46, 51). - Vanderkam admits in the preface that he reads technical books "by looking at the examples and skimming the prose", and wrote his own accordingly: the code samples stand on their own (1st ed., p. xii).
- The book's whole skeleton is public: the official repo github.com/danvk/effective-typescript has all 83 items with their "Things to Remember" summaries and every code sample as a runnable TypeScript playground.
My take, honestly
Most advice books pile up unrelated tips. Not this one. The 83 items tell the same story: how the type checker reasons. Once item 7 sinks in (a type is a set of values), TypeScript error messages stop being noise: you read them like sentences. Another rare quality: the book doesn't oversell its own language. It says plainly that TypeScript lets some errors through (a deliberate design choice), and that past a certain point, making your types cleverer does more harm than good.
Now the reservations. Chapter 6 teaches you to write types that compute other types. Necessary and well done, but it's gymnastics: 90% of devs will never perform it themselves; libraries like Zod or tRPC do it for them. A few items are well-packaged common sense. And it really is a second-step book: without six months of TypeScript behind you, three quarters of the items answer questions you haven't asked yet.
In 2026, this book has found a second job Vanderkam never planned: reviewing AI-generated code. AI produces TypeScript that compiles, but stuffed with as added to silence the compiler, type parameters that relate nothing, and contradictory states allowed by vague types. Items 5, 9, 29 and 51 describe exactly those flaws. Reading this book is learning to review the machine.
Odilon
Still relevant in 2026?
This page covers the 2nd edition (May 2024, TypeScript 5): satisfies, template literal types and recursive types are all in. Nothing in the versions released since invalidates an item: the book teaches the type system, not the tooling.
Who is it for?
Read it if
- You've written TypeScript for 6 months to 2 years and compiler errors are still gut-feeling negotiations
- Your codebase keeps collecting
anyandasadded "just to make it compile" - You review AI-generated TypeScript and want to spot the lying types
- You're planning a JS → TS migration: the last chapter is a battle-tested plan
Skip it if
- You're starting out: the official handbook and a real project first, this book in a year
- You don't write TypeScript and don't have to: everything here is language-specific
- You expect a structured course: it's a collection of 83 essays, not a pedagogical progression
For going further
Practice with the TypeScript course on this site (a real TS compiler runs in your browser), with Advanced JavaScript as the foundation. And Fluent Python plays exactly the same role on the Python side, also in this library.
Comments (0)