Type hints only provide value if something actually checks them — mypy (or alternatives like pyright) is a separate tool that analyzes your code's type hints and reports mismatches before the code ever runs.
# calculator.py
def add(a: int, b: int) -> int:
return a + b
result = add("2", "3") # a type ERROR, but Python itself won't catch this at runtime
pip install mypy
mypy calculator.py
# calculator.py:4: error: Argument 1 to "add" has incompatible type "str"; expected "int"
Running mypy calculator.py analyzes the file without executing it, cross-referencing every function call against its declared parameter and return types — the mismatched call above runs "successfully" in plain Python (string concatenation just happens to work for "2" + "3", producing "23" instead of 5), but mypy flags it immediately as a type error, catching an entire category of bugs that would otherwise only surface as unexpected runtime behavior.
Type checking is typically integrated into CI pipelines (running mypy automatically on every pull request) and into editors (VS Code's Python extension can show mypy errors inline as you type), catching mismatches the moment they're introduced rather than after a bug report from production.
mypy supports a gradual typing approach — code without any type hints is simply not checked at all, so an existing untyped codebase can adopt hints incrementally, file by file or function by function, rather than requiring a disruptive all-at-once migration. Configuration options let teams set how strict the checking should be, from lenient (only checking explicitly-annotated code) to strict (requiring hints everywhere and flagging any implicit Any type).