Topic 13 of 64
Type Hints & Annotations
Overview
Type hints (PEP 484) add optional static type information to Python code. They improve IDE support, documentation, and catch bugs early with tools like mypy. Modern Python projects and job interviews increasingly expect type hints.
Syntax
python
from typing import Optional, Union, Any, TypeVar, Generic
from typing import List, Dict, Tuple, Set # or use built-in types (3.9+)
from collections.abc import Callable, Generator, Sequence
# Function annotations
def greet(name: str, times: int = 1) -> str:
return (f"Hello, {name}! " * times).strip()
# Optional (value or None)
def find_user(id: int) -> Optional[dict]:
return db.get(id) # might return None
# Union (multiple types)
def process(value: str | int) -> str: # Python 3.10+ syntax
return str(value)
# Generic types
def first(items: list[int]) -> int | None:
return items[0] if items else None
# TypedDict
from typing import TypedDict
class User(TypedDict):
id: int
name: str
email: str
is_active: bool
# Dataclass with types
from dataclasses import dataclass
@dataclass
class Product:
id: str
name: str
price: float
stock: int = 0Common Pitfalls
- Type hints are NOT enforced at runtime by default — use mypy or pyright for static analysis.
- For Python 3.9+, use built-in generics (list[int], dict[str, int]) — no need to import from typing.
- Interview tip: TypedDict creates dict with specific key types (for JSON parsing); dataclass creates a class with typed attributes (for objects).
Real-World Example
A fully type-annotated API client:
example
python
from typing import TypeVar, Generic, Callable
from dataclasses import dataclass, field
from datetime import datetime
T = TypeVar("T")
@dataclass
class ApiResponse(Generic[T]):
data: T
status: int
message: str
timestamp: datetime = field(default_factory=datetime.now)
@dataclass
class User:
id: int
name: str
email: str
role: str = "viewer"
async def fetch_user(user_id: int) -> ApiResponse[User]:
response = await http_client.get(f"/users/{user_id}")
user_data = response.json()
user = User(**user_data)
return ApiResponse(
data=user,
status=response.status_code,
message="User fetched successfully"
)
# Usage — IDE knows the type!
result = await fetch_user(42)
print(result.data.name) # IDE autocompletes .name