Also known as: static typing, dynamic typing
Static versus dynamic typing is about when a language checks the types of its values: a statically typed language checks at compile time, before the program runs, while a dynamically typed language checks at run time, as each operation executes.1
How they differ
Under static typing, the compiler knows the type of every variable and rejects code that misuses it before you can run it — passing a string where a number is expected is a build error. Under dynamic typing, a variable can hold a string now and a number later; the interpreter only complains when an actual operation is invalid. This is a separate question from how strictly a language enforces types (strong versus weak), so the two axes combine: Rust is static and strong, Python dynamic and strong, JavaScript dynamic and weak.1
Trade-offs
Static typing catches whole classes of bugs at compile time — wrong types, missing methods, broken refactors — and makes APIs self-documenting, which is why large, long-lived codebases drift toward it. The cost is ceremony and some rigidity, though type inference removes most of the annotation burden. Dynamic typing offers flexibility and less ceremony — quick scripts, duck typing, runtime metaprogramming — at the risk of type errors that hide until that line runs.1
In practice
C, Rust, Go, and Java are statically typed; Python, Ruby, and JavaScript are dynamic. Gradual typing bridges the two: TypeScript and Python type hints add optional, checkable types to dynamic languages, keeping flexibility where you want it and adding guarantees where the code is critical.
Sources
-
Type system — static and dynamic type checking — Wikipedia, on when type checking happens and how the static/dynamic axis combines with strong/weak typing. ↩ ↩2 ↩3