Type Systems
A type system is the set of rules a language uses to categorize values and check that operations on those values make sense. It’s how a language prevents you from adding a string to a number (or lets you do it).
Why It Matters
Type errors are one of the most common bug categories. Understanding type systems helps you pick languages wisely, write safer code, and understand error messages.
Two Axes
Static vs Dynamic
| Static | Dynamic | |
|---|---|---|
| When types checked | Compile time | Runtime |
| Type annotations | Usually required | Usually optional |
| Examples | Java, Go, Rust, TypeScript | Python, JavaScript, Ruby |
| Catches bugs | Before code runs | When buggy line executes |
Strong vs Weak
| Strong | Weak | |
|---|---|---|
| Implicit conversion | No (or minimal) | Yes, lots |
| Examples | Python, Rust, Haskell | JavaScript, C, PHP |
"5" + 3 | Error | "53" (JS) or 8 (PHP) |
Code Examples
# Python: dynamic + strong
x = "hello" # no type declaration needed (dynamic)
x + 3 # TypeError: can't add str and int (strong)
x = 42 # same variable, different type now (dynamic)
# With type hints (still dynamic at runtime, but linters check)
def greet(name: str) -> str:
return f"Hello, {name}"
greet(42) # mypy would flag this, Python won't stop it// JavaScript: dynamic + weak
"5" + 3 // "53" (string concatenation — coercion!)
"5" - 3 // 2 (numeric subtraction — coercion!)
true + true // 2 (booleans coerced to numbers)
[] + {} // "[object Object]" (wat)// Go: static + strong
var x int = 5
var y float64 = 3.14
// z := x + y // compile error: mismatched types
z := float64(x) + y // explicit conversion requiredType Inference
Many static languages can figure out types without you writing them:
// Rust infers types from usage
let x = 42; // inferred as i32
let y = 3.14; // inferred as f64
let names = vec!["Alice", "Bob"]; // inferred as Vec<&str>Gradual Typing
Some dynamic languages now support optional static checking:
- Python — type hints + mypy
- JavaScript — TypeScript
- PHP — type declarations (since PHP 7)
This gives you the flexibility of dynamic typing with the safety of static checking where you want it.
Related
- Compilers vs Interpreters — static types need a compile step to check
- How Computers Execute Code — types determine how values are stored
- Big O Notation — type choice affects performance (int vs bigint)