The typing module provides type hints for static analysis. Here's everything you need for everyday use.
Basic Types
# Built-in types (no import needed in 3.9+)
x: int = 1
y: float = 2.0
z: str = "hello"
flag: bool = True
data: bytes = b"data"
# None
def no_return() -> None:
print("nothing")Collections
Python 3.9+ uses built-in types directly:
# Modern syntax (3.9+)
numbers: list[int] = [1, 2, 3]
mapping: dict[str, int] = {"a": 1}
items: set[str] = {"x", "y"}
coords: tuple[int, int] = (1, 2)
# Pre-3.9 (from typing import)
from typing import List, Dict, Set, Tuple
numbers: List[int] = [1, 2, 3]Optional and Union
from typing import Optional, Union
# Optional = Union[X, None]
def find(key: str) -> Optional[str]:
return cache.get(key)
# Union for multiple types
def process(value: Union[int, str]) -> str:
return str(value)
# Modern syntax (3.10+)
def find(key: str) -> str | None:
return cache.get(key)
def process(value: int | str) -> str:
return str(value)Callable
from typing import Callable
# Function that takes two ints, returns str
Handler = Callable[[int, int], str]
def apply(fn: Callable[[int], int], x: int) -> int:
return fn(x)
# Any callable
from typing import Any
fn: Callable[..., Any]TypeVar and Generic
from typing import TypeVar, Generic
T = TypeVar('T')
def first(items: list[T]) -> T:
return items[0]
# Bounded TypeVar
Number = TypeVar('Number', int, float)
def double(x: Number) -> Number:
return x * 2
# Generic class
class Stack(Generic[T]):
def __init__(self) -> None:
self._items: list[T] = []
def push(self, item: T) -> None:
self._items.append(item)
def pop(self) -> T:
return self._items.pop()
stack: Stack[int] = Stack()Literal
from typing import Literal
Mode = Literal["r", "w", "a"]
def open_file(path: str, mode: Mode) -> None:
pass
open_file("test.txt", "r") # OK
open_file("test.txt", "x") # Type errorTypedDict
from typing import TypedDict
class User(TypedDict):
name: str
age: int
email: str
def process_user(user: User) -> None:
print(user["name"])
# Optional keys
class Config(TypedDict, total=False):
debug: bool
timeout: intProtocol (Structural Subtyping)
from typing import Protocol
class Drawable(Protocol):
def draw(self) -> None: ...
class Circle:
def draw(self) -> None:
print("Drawing circle")
def render(shape: Drawable) -> None:
shape.draw()
# Circle matches Drawable without explicit inheritance
render(Circle())Final and ClassVar
from typing import Final, ClassVar
class Config:
VERSION: Final[str] = "1.0.0" # Can't reassign
instance_count: ClassVar[int] = 0 # Class variable
MAX_SIZE: Final = 100 # Inferred typeSelf Type (3.11+)
from typing import Self
class Builder:
def set_name(self, name: str) -> Self:
self.name = name
return self
def set_value(self, value: int) -> Self:
self.value = value
return selfType Aliases
from typing import TypeAlias
# Simple alias
Vector: TypeAlias = list[float]
# Complex alias
JSON: TypeAlias = dict[str, "JSON"] | list["JSON"] | str | int | float | bool | None
# NewType for distinct types
from typing import NewType
UserId = NewType('UserId', int)
def get_user(user_id: UserId) -> User:
pass
# Must explicitly convert
user_id = UserId(123)Any and object
from typing import Any
# Any: opt out of type checking
def dangerous(x: Any) -> Any:
return x.whatever()
# object: base of all types, but type-safe
def safe(x: object) -> str:
return str(x)
# x.whatever() # Error: object has no attribute 'whatever'Overload
from typing import overload
@overload
def process(x: int) -> int: ...
@overload
def process(x: str) -> str: ...
def process(x: int | str) -> int | str:
if isinstance(x, int):
return x * 2
return x.upper()Type Guards (3.10+)
from typing import TypeGuard
def is_string_list(val: list[object]) -> TypeGuard[list[str]]:
return all(isinstance(x, str) for x in val)
def process(items: list[object]) -> None:
if is_string_list(items):
# items is now list[str]
print(items[0].upper())ParamSpec (3.10+)
from typing import ParamSpec, TypeVar, Callable
P = ParamSpec('P')
R = TypeVar('R')
def decorator(fn: Callable[P, R]) -> Callable[P, R]:
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
print("Before")
return fn(*args, **kwargs)
return wrapperQuick Reference
| Type | Meaning |
|---|---|
int, str, float | Basic types |
list[T] | List of T |
dict[K, V] | Dict with K keys, V values |
tuple[T, ...] | Variable-length tuple |
tuple[T, U] | Fixed-length tuple |
T | None | Optional (3.10+) |
Optional[T] | Optional (pre-3.10) |
T | U | Union (3.10+) |
Callable[[Args], Ret] | Function type |
TypeVar('T') | Generic type variable |
Any | Opt out of checking |
Version Guide
| Feature | Version |
|---|---|
list[int] syntax | 3.9+ |
X | Y union | 3.10+ |
TypeGuard | 3.10+ |
ParamSpec | 3.10+ |
Self | 3.11+ |
TypedDict Required/NotRequired | 3.11+ |
Type hints are documentation that tools can verify. Use them.
React to this post: