Skip to content

Practical Mastery

You now know how the type system works. This module is about using it well — the judgment calls that separate someone who can pass the compiler from someone who ships maintainable TypeScript.

The through-line is one uncomfortable truth: the compiler only knows what you tell it. Types are a model of your program, and a model can be wrong. An any, a bad cast, or a JSON blob from the network can all lie to the checker. Mastery is knowing where the model meets reality and defending that boundary.

LessonWhat you’ll learn
Typing APIs & boundariesunknown vs any, validating external data, branded types
Nullability & neverstrictNullChecks, Result types, exhaustiveness with never
Performance & pitfallsWhy tsc gets slow, common footguns, when to simplify
Migration strategyMoving a JS codebase to TS without a big-bang rewrite
flowchart LR
  world["untyped world
network, JSON, any, casts"] -->|validate at the edge| edge["boundary
(guards, schemas)"]
  edge -->|trusted types| inside["your typed code
(safe to trust)"]
The typed island in an untyped sea

Everything here is a variation on validate at the edge, trust inside. Push the uncertainty to the boundary of your program, turn it into real types there, and let the whole interior enjoy the guarantees. Get the boundary right and the type system pays you back everywhere else.

What is the central truth of this module?
What is the recurring strategy for handling the untyped world?
A project compiles with zero errors. What does that guarantee?