Type systems

A type system is the set of rules a programming language uses to classify values into types, such as integer, string, or a user-defined structure, and to constrain which operations are valid on values of each type. Its main job is to catch a category of mistake, such as passing a string where a number is expected, before it causes incorrect behavior.

The main design choice is when those rules are checked. A statically typed language checks types at compile time, against the source code itself, so a whole class of errors surfaces before the program ever runs. TypeScript and Java are examples. A dynamically typed language checks types at runtime, against the actual value a variable holds at the moment it’s used. Python, PHP, and untyped JavaScript are examples.

Static typing catches more mistakes earlier at the cost of more upfront annotation. Dynamic typing is faster to write but pushes type errors to runtime, where they surface as failures rather than as warnings from a compiler.

A further distinction is structural versus nominal typing — whether two types are considered compatible because their shapes match (also called duck typing), or only because they share a declared name or ancestry.

Most type systems also support generics, letting a function or structure be written once and parameterized over the type it operates on, such as a list that can hold any single element type while still being checked at compile time.