How to Use TypedDict and Dataclasses in Python
Create typed data structures with TypedDict and dataclasses, then use them as helper functions for describing objects in a type-safe way.
Python code
33 linesfrom typing import TypedDict, NotRequired, Optional
from dataclasses import dataclass
class User(TypedDict):
name: str
age: NotRequired[int]
email: Optional[str]
@dataclass
class Product:
id: int
title: str
price: float = 0.0
def describe_user(user: User) -> str:
age = user.get("age", "unknown")
email = user.get("email", "not provided")
return f"{user['name']} (age: {age}, email: {email})"
def describe_product(product: Product) -> str:
return f"Product #{product.id}: {product.title} — ${product.price:.2f}"
if __name__ == "__main__":
sample_user: User = {"name": "Alice", "email": None}
sample_product = Product(id=101, title="Keyboard", price=49.99)
print(describe_user(sample_user))
print(describe_product(sample_product))
Output
Alice (age: unknown, email: not provided)
Product #101: Keyboard — $49.99
How it works
TypedDict defines a dictionary schema with optional keys (NotRequired) and nullable fields (Optional), enabling type checking on dict-like structures. The dataclass decorator auto-generates __init__, __repr__, and equality methods, reducing boilerplate for class-based data. Helper functions like describe_user and describe_product provide single-responsibility formatting, leveraging type hints for better IDE support and static analysis. Optional[str] means the value can be None or a string, while get() with defaults makes handling missing keys safe at runtime.
Common mistakes
- Using `Optional[int]` instead of `NotRequired[int]` when the key may be absent entirely
- Forgetting that `TypedDict` is checked statically, not at runtime — invalid keys won't raise errors
- Omitting `from __future__ import annotations` when mixing dataclasses and TypedDicts in older Python versions
Variations
- Use `typing.Protocol` for structural subtyping instead of `TypedDict`
- Define dataclass fields with `field(default_factory=...)` for mutable defaults
Real-world use cases
- Typing API payloads in a client library so endpoint responses are validated by the type checker.
- Defining immutable config objects with dataclasses and defaults for application settings.
- Building helper formatters that display user or product data consistently across a web UI.
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.