How to Use Python Type Hints for Beginners
Build a data helper module with basic type hints — Union, Optional, List, Dict, Any, and TypeVar — to make your code clearer and safer.
Python code
40 linesfrom typing import Any, Union, Optional, List, Dict, Tuple, Callable, TypeVar
T = TypeVar("T")
def describe(value: Any) -> str:
"""Return a human-readable description of the value's type."""
if isinstance(value, list):
return f"list of {len(value)} items"
elif isinstance(value, dict):
return f"dict with {len(value)} keys"
elif isinstance(value, str):
return f"string ({len(value)} chars)"
elif isinstance(value, (int, float)):
return f"number: {value}"
elif value is None:
return "None"
else:
return f"instance of {type(value).__name__}"
def double(x: Union[int, float]) -> Union[int, float]:
"""Double a number."""
return x * 2
def greet(name: Optional[str] = None) -> str:
"""Greet a person, or everyone if no name given."""
if name is None:
return "Hello, everyone!"
return f"Hello, {name}!"
def process_items(items: List[int]) -> Dict[str, int]:
"""Summarize a list of numbers."""
return {"total": sum(items), "count": len(items), "max": max(items) if items else 0}
if __name__ == "__main__":
print(describe([1, 2, 3]))
print(describe({"a": 1}))
print(double(5))
print(greet())
print(greet("Alice"))
print(process_items([3, 7, 2]))
Output
list of 3 items
dict with 1 keys
10
Hello, everyone!
Hello, Alice!
{'total': 12, 'count': 3, 'max': 7}
How it works
Type hints are optional annotations that tell tools like mypy and your IDE what types functions expect and return. Optional[str] is shorthand for Union[str, None], and List[int] means a list of integers. Any says 'any type is allowed' and disables checking for that value. TypeVar lets you write generic functions that work with multiple types while keeping the relationship between inputs and outputs. These hints don't change runtime behavior — they exist for documentation and static analysis.
Common mistakes
- Forgetting `Optional` when a parameter can be `None` — use `Optional[str] = None` instead of `str = None`.
- Using `list` instead of `List` in older Python versions — `List` works everywhere in 3.9+.
- Type hints don't enforce anything at runtime — you still need to validate input if it comes from users.
Variations
- Use `from __future__ import annotations` to write hints as strings and defer evaluation, allowing built-in generics like `list[int]`.
- Replace `Union[int, float]` with `int | float` in Python 3.10+ for cleaner syntax.
Real-world use cases
- Documenting function signatures in a shared library so teammates know exactly what to pass and expect back.
- Enabling static type checking in CI with mypy to catch bugs before they reach production.
- Improving IDE autocomplete and jump-to-definition for a large Python codebase.
Sponsored
More from Testing & modern typing
- Capture stdout and stderr with pytest capsys easy
- Characterization Test for Legacy Python Code medium
- Dataclass with Type Hints Fields in Python easy
- Dependency Injection in Python for Testability easy
- Design Data Helpers with Python TypedDict and Literal easy
- Fix and Test a Regression Bug in Python with Unit Tests easy
Keep learning
Related tutorials and quizzes for this topic.