Also known as: type system
A type system is the set of rules a language uses to track the type of every value
— integer, string, list, a Receiver object — and decide which operations are allowed,
catching whole classes of mistakes that would otherwise surface as bugs.1
How it works
The type system assigns a type to each value and to the inputs and outputs of every operation, then verifies that uses line up. When it checks is the static-versus-dynamic axis: a compiled language usually checks at compile time, while a dynamic language checks at run time as each operation executes. A separate axis is how strictly it enforces types — strong systems refuse to silently mix a string and a number, weak ones coerce. Type inference lets the compiler deduce types from context, so you get checking without spelling out every annotation.1
Trade-offs
A richer type system pays for itself by turning run-time surprises into compile errors: wrong-type arguments, calling a method that does not exist, forgetting to handle a null, and broken refactors all get caught for free.1 Expressive features — generics, sum types, and Option/Result types — let you “make illegal states unrepresentable.” The cost is ceremony, some rigidity, and slower prototyping. A throwaway script barely benefits; a large, long-lived, multi-author system benefits enormously.
In practice
Rust, Go, and Java pair static checking with inference; TypeScript adds a checkable type layer over JavaScript. In domains like radio software, wrapping a frequency and a sample rate in distinct types makes unit-confusion bugs impossible to compile rather than merely unlikely.
Sources
-
Type system — Wikipedia, on type checking, the static/dynamic and strong/weak axes, type inference, and type safety. ↩ ↩2 ↩3