Two independent axes of type systems
A language’s type system is usually described along two separate axes: when types are checked (static, dynamic or gradual) and how strictly mismatches are handled (strong or weak). These are independent — Python is dynamic but strong, C is static but weak. This reference compares both axes across major languages, along with nominal-versus-structural and type-inference notes.
How it works
The checking axis is about timing; the strength axis is about coercion:
Strong typing Weak typing
Static Rust, Java, Haskell, Go C, (C++ casts)
Dynamic Python, Ruby, Clojure JavaScript, PHP, Perl, Lua
Gradual TypeScript, Python+hints —
A third dimension is how types are compared. Nominal systems match by declared
name (a Dog is a Dog), while structural systems match by shape — Go
interfaces and TypeScript accept any value with the right members. Duck typing
is the dynamic cousin: “if it responds to the method, use it.” The filter lets you
slice the table by checking model and search by name or concept.
Tips and notes
- “Strong” and “static” are not synonyms — keep the two axes separate when reasoning.
- Structural typing (Go, TypeScript) reduces boilerplate but can hide accidental matches.
- Gradual systems let you add types incrementally;
anyis the escape hatch that weakens guarantees. - Type inference (Rust, Haskell, Kotlin) keeps static code concise without losing safety.