APIs and config files produce dicts; TypedDict lets you check key names and value types without converting to classes.
dict[str, Any] says nothing about which keys exist. A TypedDict declares them:
class Movie(TypedDict):
title: str
year: intAt runtime a Movie is a plain dict; Movie(title="x", year=1) just builds one. The checker, however, knows m["title"] is a str, flags typos like m["titel"], and rejects missing or extra keys in literals.
Key presence:
- All keys are required by default.
total=Falsemakes all of them optional. NotRequired[T]marks individual keys optional;Required[T]does the reverse inside atotal=Falseclass.- Use
m.get("key")for optional keys; the result type includesNone.
`ReadOnly[T]` (3.13, PEP 705) marks keys that must not be assigned through this type, which lets a function accepting a "read-only view" take TypedDicts with compatible but narrower value types.
TypedDicts support inheritance and generics. The alternative functional syntax, Movie = TypedDict("Movie", {"title": str}), works for keys that aren't valid identifiers.
Choose TypedDict for data that stays a dict (JSON, kwargs); choose a dataclass when you want an object with methods.
Example
from typing import NotRequired, ReadOnly, TypedDict
class User(TypedDict):
id: ReadOnly[int]
name: str
email: NotRequired[str]
def greeting(u: User) -> str:
domain = u.get("email", "no email") # optional key: use get()
return f"{u['name']} <{domain}>"
u: User = {"id": 1, "name": "Ada"}
print(greeting(u), type(u).__name__) # Ada <no email> dict
print(User.__required_keys__, User.__optional_keys__)
# frozenset({'id', 'name'}) frozenset({'email'}) (set order may vary)
# u["nmae"] -> checker error: TypedDict "User" has no key "nmae"
# u["id"] = 2 -> checker error: ReadOnly key "id" cannot be assigned
# bad: User = {"name": "x"} -> checker error: missing key "id"Remember
- TypedDict types dicts with known keys; at runtime it's a plain dict
- NotRequired / total=False mark optional keys
- ReadOnly (3.13) forbids assignment to a key
Watch out for
- Expecting runtime validation; TypedDict(...) accepts any values, only the checker complains.