The post takes the old “parse, don’t validate” idea from functional programming and shows how to approximate it in TypeScript. Instead of checking raw strings and booleans over and over, you parse them once into domain-specific types like Email or VerifiedUser and then write the rest of the code against those narrower types. In TypeScript that usually means branded types, discriminated unions, parser functions, and runtime schema tools like Zod, because the language is structurally typed and erases types at runtime. Several people liked the framing because it pushes validation to the boundary where data enters the system, then lets the compiler enforce cleaner invariants inside the app.
The useful consensus was not “model everything as ever-more-refined types.” It was much narrower. Parse requests, database rows, environment variables, and URL params. Use branded or derived types where the distinction actually prevents real mistakes, especially for external inputs that otherwise stay as anonymous strings. Keep optional fields as `T | null` when absence is a real domain state. Reach for separate types or discriminated unions only when fields move together as a meaningful state transition. That keeps the idea from collapsing into a combinatorial mess of `UserWithBirthdayAndEmailAndVerification` variants.
A lot of the discussion landed on TypeScript’s ceiling. Because TS is structural, not nominal, and because JavaScript objects are still just JavaScript objects at runtime, you cannot get the same guarantees you would in languages that can hide constructors or enforce newtypes natively. Branding helps because it is zero-cost at runtime, but it is still a type-system trick, not a runtime boundary. That is why many people framed Zod as the sweet spot. It gives you an explicit parse step and useful runtime guarantees without demanding a whole new architecture. Others preferred generating
JSON Schema from TypeScript types and validating with
Ajv, mainly to avoid locking domain modeling to a runtime schema library and to get
OpenAPI reuse.
The sharper pushback was that the article’s example sometimes looked more like “validate once, then tag the value” than true parsing into a structure that encodes the invariant itself. For some domains that distinction matters. A branded email string tells you validation happened. A parsed email object with separate local-part and domain can encode more of the invariant in the shape itself. Even people making that objection still converged on the same practical lesson. In TypeScript, carry stronger guarantees where they buy clarity or safety, but stop well short of trying to represent every conceivable business predicate in the type system. The gain comes from reducing repeated checks and accidental misuse at the edges, not from proving your SaaS app correct.