Typing
A track of P31 · Typing & Robust Code.
Gradual typing that pays for itself: annotations as a contract mypy checks in CI, Optional and | None to force the missing case, and generics, Protocols and ParamSpec for the tricky parts - graded by inspecting the types themselves.
"Python is dynamically typed, so why bother annotating?" is the question every
engineer asks once — usually right before an AttributeError: 'NoneType' takes
down production. The answer is gradual typing: annotations are optional, cost
nothing at runtime, and a checker like mypy reads them to turn a whole class of
bugs into a red build on the PR instead of a 2am page.
This track teaches types as a contract you can inspect. You annotate functions
and their Optional returns (X | None, which forces the caller to handle the
missing case), build a generic Stack[T] so one class is type-safe for any
element, meet Protocols — structural "anything with this shape" typing, the
duck typing a checker understands — and finally type a decorator with
ParamSpec, the piece P29 was missing. Because the browser can't run mypy,
every rung grades the annotations by reading them back with typing.get_type_hints
— the exact information a type checker consumes — so a function that lies about its
types, or forgets them, fails.
It closes with the capstone: take a real, untyped Cart module to a green type
contract. Paired with P30's test suite for the same module, that is the
discipline's promise made concrete — untested and untyped becomes tested and typed.