Frontend

Type System Design

Composing types and representing absence: unions, intersections, algebraic data types, exhaustive pattern matching, nullability and gradual typing.

Union Types

A union says a value is one of several types. That is only useful if the checker can find out *which* one — so the real subject of this lesson is narrowing, and the discriminant that makes narrowing possible.

Q · When is `string | number` actually useful, and why does my code still not compile after I have checked the type?
Intersection Types

`A & B` is a value that satisfies both constraints at once. It is the right tool for mixins and for refining an over-broad type, and it will cheerfully let you write a type that no value can ever have.

Q · What does `A & B` actually give me, and why does `string & number` type-check when nothing can ever be one?
Algebraic Data Types

Products hold several things at once; sums hold exactly one of several things. The word "algebraic" is literal — cardinalities multiply for products and add for sums — and that arithmetic is the fastest way to tell whether a data model can represent states that must never exist.

Q · Why are enums with payloads called "algebraic", and when should I reach for one instead of a struct with a few optional fields?
Pattern Matching

Matching is the elimination form for a sum type: it inspects the tag and binds the payload in one construct. Destructuring, guards, nested patterns and bindings are the surface; the decision tree the compiler builds from it is a separate subject.

Q · What does `match` give me that a chain of `if` statements and field accesses does not?
Exhaustiveness Checking

The compiler proves that every variant is handled, and reports a concrete value if one is not. This is the payoff that makes sum types worth having — and the reason adding a variant is a breaking change.

Q · How do I make the compiler tell me every place I need to update when I add a variant?
Nullability and Optional Types

Two ways to represent absence: a type that silently includes an extra value and a flow analysis to exclude it, or an ordinary sum type with no special status at all. They differ in what they cost you at the boundary, in the signature, and in bytes.

Q · Should absence be a nullable type or an `Option`, and what does each actually cost at runtime?
Gradual Typing

Static and dynamic typing in one program, with a dynamic type that is compatible with everything. The honest version of the story includes what `any` costs, why TypeScript checks nothing at runtime, and why the sound alternative has a performance problem nobody has fully solved.

Q · If TypeScript checks my types, why does a value of the wrong type still reach production?