Static Type Checking — mypy
The “TypeScript moment” for Python
Section titled “The “TypeScript moment” for Python”When you first learned TypeScript you probably experienced the moment where the compiler caught a real bug before you even ran the code. Python’s type hints give you the same capability — but the interpreter itself never checks them. mypy is the separate static analysis tool that performs that check.
Think of mypy as tsc --noEmit for Python: it reads your annotations and reports type errors without running or compiling anything.
Installing and running
Section titled “Installing and running”Run this in your terminal:
pip install mypy# or:uv add --dev mypy
# Check a single filemypy src/main.py
# Check entire packagemypy src/
# Strict mode (equivalent to tsconfig "strict: true")mypy --strict src/Annotating Python vs TypeScript
Section titled “Annotating Python vs TypeScript”// TypeScript — types enforced by compilerfunction greet(name: string): string { return `Hello, ${name}!`;}
function add(a: number, b: number): number { return a + b;}
// Genericfunction first<T>(arr: T[]): T | undefined { return arr[0];}# Python — types checked by mypy, ignored by interpreterdef greet(name: str) -> str: return f"Hello, {name}!"
def add(a: int, b: int) -> int: return a + b
# Generic (Python 3.12+ syntax)def first[T](arr: list[T]) -> T | None: return arr[0] if arr else NoneCommon type annotations
Section titled “Common type annotations”// TypeScript common typesconst names: string[] = ["Alice", "Bob"];const scores: Map<string, number> = new Map();const user: { name: string; age: number } | null = null;
// Optional parameterfunction find(id: number, strict?: boolean): string | null { return null;}
// Uniontype Result = { ok: true; value: string } | { ok: false; error: string };# Python 3.10+ common typesfrom typing import Optional
names: list[str] = ["Alice", "Bob"]scores: dict[str, int] = {}user: dict[str, str | int] | None = None
# Optional parameter (None default = Optional)def find(id: int, strict: bool = False) -> str | None: return None
# TypedDict for structured dictsfrom typing import TypedDict
class OkResult(TypedDict): ok: bool value: strTry it — type hints in action
Section titled “Try it — type hints in action”from typing import Optional
def double(x: int) -> int: return x * 2
def greet(name: str) -> str: return f"Hello, {name}!"
# These are fineprint(double(5))print(greet("Alice"))
# Type hints don't stop this at runtime:result = double("oops") # mypy would flag this, Python runs itprint(result) # prints 'oopsoops' — string * 2 repeats it!Loading Python runtime (first run only)…
Configuring mypy vs tsconfig
Section titled “Configuring mypy vs tsconfig”// tsconfig.json{ "compilerOptions": { "strict": true, "noImplicitAny": true, "strictNullChecks": true, "target": "ES2022", "module": "NodeNext" }}# pyproject.toml [tool.mypy] section[tool.mypy]python_version = "3.11"strict = true # enables all strict checkswarn_return_any = truedisallow_untyped_defs = trueignore_missing_imports = true # for untyped third-party libs