Type Hints in Python
Type hints add optional static typing using annotations checked by tools like mypy/pyright.
Function and variable annotations
Annotate parameters, returns, and variables.
from typing import List
def add(a: int, b: int) -> int: ...
count: int = 0
names: List[str] = ["Ada", "Guido"]
Unions and Optionals (PEP 604)
Use | for unions and | None for optionals.
from typing import Optional
val: int | str
maybe: Optional[int] = None # same as int | None
Literals and enums
Constrain to specific values.
from typing import Literal
role: Literal["user", "admin"]
Generics and TypeVars
Write generic functions and classes.
from typing import TypeVar, Iterable, Sequence
T = TypeVar('T')
def first(xs: Sequence[T]) -> T: return xs[0]
Protocols and structural typing
Protocols specify required methods; any type matching the method set is accepted.
from typing import Protocol
class SupportsClose(Protocol):
def close(self) -> None: ...
def cleanup(x: SupportsClose) -> None:
x.close()
TypedDict and dataclasses
Model dict‑like records with TypedDict or use @dataclass for structured types.
from typing import TypedDict
class UserTD(TypedDict):
id: int
name: str
NewType and type aliases
NewType provides distinct nominal types; aliases improve readability.
from typing import NewType
UserId = NewType("UserId", int)
JSON = dict[str, object]
Any and cast
Use Any sparingly; prefer precise types. Use cast for narrowing when the checker cannot infer.
from typing import Any, cast
x: Any = fetch()
y = cast(str, x)
Best practices
- Add hints to public APIs first; annotate gradually
- Prefer precise, readable types over overly clever expressions
- Keep runtime behavior unchanged; hints are for tooling
Summary
- Use annotations, unions, generics, and protocols to document and check intent
- Favor gradual typing and clear models (
TypedDict, dataclasses)