TypedDict Request/Response¶
Type hints only - Uses TypedDict for static type checking with zero runtime overhead.
Best For¶
- Type hints for dictionaries
- Static type checking (mypy)
- When you need zero runtime overhead
- Integration with existing dict-based code
No Runtime Validation
TypedDict is only for static type checking. It doesn't provide runtime validation or instance creation. You'll need to implement to_dict() and from_dict() manually. TypedDict cannot directly implement IRequest/IResponse, so a wrapper class is required.
Usage¶
Since TypedDict cannot directly implement IRequest/IResponse, we use a wrapper class:
import cqrs
from typing import TypedDict, Self
# Define TypedDict for type hints
class TypedDictRequestDict(TypedDict):
"""Type definition for request dictionary."""
user_id: str
action: str
class TypedDictRequest(cqrs.IRequest):
"""Request using TypedDict for type hints."""
def __init__(self, user_id: str, action: str):
self.user_id = user_id
self.action = action
def to_dict(self) -> TypedDictRequestDict:
"""Convert to dictionary."""
return {
"user_id": self.user_id,
"action": self.action
}
@classmethod
def from_dict(cls, **kwargs) -> Self:
"""Create from dictionary."""
return cls(
user_id=kwargs["user_id"],
action=kwargs["action"]
)
class TypedDictResponseDict(TypedDict):
"""Type definition for response dictionary."""
result: str
status: str
class TypedDictResponse(cqrs.IResponse):
"""Response using TypedDict for type hints."""
def __init__(self, result: str, status: str):
self.result = result
self.status = status
def to_dict(self) -> TypedDictResponseDict:
"""Convert to dictionary."""
return {
"result": self.result,
"status": self.status
}
@classmethod
def from_dict(cls, **kwargs) -> Self:
"""Create from dictionary."""
return cls(
result=kwargs["result"],
status=kwargs["status"]
)
Optional Fields¶
You can use NotRequired for optional fields:
from typing import TypedDict, NotRequired
class OptionalFieldsDict(TypedDict):
user_id: str
action: str
metadata: NotRequired[dict]
class OptionalFieldsRequest(cqrs.IRequest):
def __init__(self, user_id: str, action: str, metadata: dict | None = None):
self.user_id = user_id
self.action = action
self.metadata = metadata or {}
def to_dict(self) -> OptionalFieldsDict:
result: OptionalFieldsDict = {
"user_id": self.user_id,
"action": self.action
}
if self.metadata:
result["metadata"] = self.metadata
return result
@classmethod
def from_dict(cls, **kwargs) -> Self:
return cls(
user_id=kwargs["user_id"],
action=kwargs["action"],
metadata=kwargs.get("metadata")
)
Total vs Non-Total¶
You can control whether all fields are required:
# Total=True (default) - all fields required
class TotalDict(TypedDict, total=True):
user_id: str
action: str
# Total=False - all fields optional
class NonTotalDict(TypedDict, total=False):
user_id: str
action: str
When to Use¶
Consider using TypedDict when:
- You need static type checking only
- Runtime overhead must be zero
- You're working with existing dict-based code
- You want type hints without runtime validation
See Also¶
- Standard Classes - Similar approach with more flexibility
- Request Handlers - Learn about handler implementation