Type Theory, A Very Rudimentary Introduction#
In mathematics and theoretical computer science, a type theory is the formal presentation of a specific type system. The lineage of type theory can be traced back to after the development of set theory in the late 19th century where it is born out of the need to avoid the Russell’s paradox. Muñoz[1] gives a gentle survey of this history and of type theory’s applications in computer science.
In the context of computer science and programming, it is known that static program analysis, such as the type checking algorithms in the semantic analysis phase of compilers, can be used to detect type errors at static-analysis time - and has deep connections to type theory.
In what follows, I will provide a very rudimentary introduction to type theory. The series of posts serve more as a reflection and learning experience for me than an in-depth guide. We will walk through the basic concepts of type theory and its applications in computer science. Most examples will be in Python, but the concepts — subtype relationships, type safety, variance — apply across statically checked languages like Java, C#, and TypeScript.
How to read this series#
The canonical reference for Python’s type system today is the maintained typing specification. The foundational PEPs — PEP 483, The Theory of Type Hints and PEP 484, Type Hints by Guido van Rossum and Ivan Levkivskyi — remain worth reading as historical design records, but where they and the specification disagree, the specification wins.
Conventions used throughout the series:
Code examples target Python 3.14 and use modern syntax (PEP 695 type parameters, builtin generics,
X | Yunions). Legacy forms (TypeVar(...),Generic[T], capitalizedtypingaliases) appear only in sidebars explicitly labeled as legacy.Every static-analysis claim is verified against pyright and mypy; where the two checkers disagree, both outputs are shown.
Runtime-demonstrable behavior runs in executed code cells; checker-rejected code lives in static blocks with the checker’s actual output.
Roadmap#
Subtypes — types as sets of values; nominal versus structural subtyping; where structural subtyping meets the Liskov substitution principle.
Type Safety — safe substitution; why
intis promoted to, not a subtype of,float; static, dynamic, and gradual typing.Subsumption — the formal three-part criterion for subtypehood; reflexivity and transitivity; narrowing values and widening functions.
Generics — motivation for parameterized types; type variables, parameters, and arguments; generic classes, functions, and methods.
PEP 695: The Type Parameter Syntax (upcoming) — declaration sites, scoping rules, the
typealias statement, lazy evaluation, and when legacyTypeVarsurvives.Bounds and Constraints — restricting type variables by upper bounds and constraint sets (and, soon, defaults per PEP 696).
Invariance, Covariance, Contravariance — variance of type constructors; mutability’s role; contravariance of
Callablearguments.Type Narrowing:
TypeIsandTypeGuard(upcoming) — user-defined predicates, and whyTypeIssoundness is a subtyping condition.Function Overloading —
@overloadvariants, runtime behavior, single dispatch, and unsafe overlapping overloads.TypedDict and
ReadOnly(upcoming) — structural typing of dict-shaped data; read-only keys as the payoff of the variance chapter.Sentinel Values —
NotGiven/Missingsingletons, why hand-rolled sentinels defeat narrowing, and the modern idioms.Annotations at Runtime (upcoming) — PEP 649/749 deferred evaluation,
annotationlib, and the end offrom __future__ import annotations.
Table of Contents#
Further Reading#
Z. Luo, S. Soloviev, and T. Xue, “Coercive subtyping: Theory and implementation”, Information and Computation, vol. 223, pp. 18–42, Feb. 2013. doi:10.1016/j.ic.2012.10.020 — formal treatment of the coercive implementation of subtyping discussed at the end of the subtypes chapter.
Python typing specification — the living, canonical description of the type system the checkers implement.