typeddict 仅用于静态类型检查,无法运行时校验;需配合手动断言或 typeguard 等工具实现运行时验证,嵌套结构须逐层定义具体 typeddict 类型。

TypedDict 不能直接校验运行时数据,它只做类型检查
很多人以为 TypedDict 像 Pydantic 那样能自动验证 API 返回的 dict 是否符合结构——其实不能。TypedDict 是纯静态类型提示工具,mypy 或 IDE 在编码阶段报错,但 Python 解释器完全无视它。你传一个缺字段、类型错、多字段的 dict 给标注了 TypedDict 的函数,程序照常运行,直到你访问不存在的 key 才抛 KeyError 或类型错误。
所以关键分两步:先用 TypedDict 定义结构(给编辑器和类型检查器看),再手动或借助轻量工具做运行时校验。
定义嵌套 TypedDict 时,必须显式标注所有层级的子类型
API 响应常见嵌套对象(如 "user": {"id": 1, "profile": {"name": "Alice"}}}),这时不能写 profile: dict——这会丢失内部结构信息,也无法被 mypy 检查字段名和类型。必须逐层定义:
from typing import TypedDict, List, Optional <p>class UserProfile(TypedDict): name: str avatar_url: Optional[str]</p><p>class User(TypedDict): id: int email: str profile: UserProfile # ← 必须是具体 TypedDict 类型,不能是 dict</p><p>class ApiResponse(TypedDict): success: bool data: User tags: List[str] </p>
注意点:
-
Optional[...]和NotRequired[...]要区分:前者表示字段存在但值可为None;后者(Python 3.11+)表示字段可选(可能根本不存在) - 如果字段是列表嵌套对象,写
List[User],不是list[User](后者在 3.11 中虽可用,但兼容性差,mypy 对list泛型支持不稳定) - 字段名含连字符(如
"first-name")无法直接作属性名,得用字符串索引,且需配合total=False和NotRequired
运行时校验得靠自己写断言或用 simplejson + typeguard
最轻量的做法是写个校验函数,利用 isinstance + get + 类型检查组合判断。不推荐用 jsonschema 这类重型方案,除非你已有 schema 文件。
示例(仅校验必要字段和基础类型):
def validate_api_response(obj: dict) -> ApiResponse:
if not isinstance(obj, dict):
raise TypeError("response must be dict")
if not isinstance(obj.get("success"), bool):
raise TypeError("missing or invalid 'success'")
if not isinstance(obj.get("data"), dict):
raise TypeError("missing or invalid 'data'")
# 手动校验 data 字段结构
data = obj["data"]
if not isinstance(data.get("id"), int):
raise TypeError("data.id must be int")
if not isinstance(data.get("profile"), dict):
raise TypeError("data.profile missing or not dict")
profile = data["profile"]
if not isinstance(profile.get("name"), str):
raise TypeError("data.profile.name missing or not str")
return obj # 类型检查器此时可推导为 ApiResponse
更稳妥的选择是搭配 typeguard 库(安装:pip install typeguard):
- 它支持对
TypedDict实例做运行时类型检查 - 只需加装饰器
@typechecked或调用check_type(value, ApiResponse) - 对嵌套
TypedDict和NotRequired字段支持良好 - 性能开销小,适合 API 响应校验这种低频场景
和 Pydantic v2 混用时,TypedDict 只能当类型注解,不能当模型基类
如果你项目里已用 Pydantic,别试图把 TypedDict 当 BaseModel 用——它没有 .model_validate()、不支持默认值、无字段别名映射(alias)、也不能自动处理 datetime 解析。常见误操作:
- 写
ApiResponse.model_validate(resp_json)→ 报错,TypedDict没这个方法 - 想用
Field(default=...)→ 不支持,TypedDict里只能靠NotRequired或文档约定 - 期望它自动转换字符串数字为
int→ 不会,Pydantic 才干这事
合理做法是:用 TypedDict 做接口返回类型的“契约声明”,在调用处用 Pydantic 模型接收并校验,再转成 TypedDict 注解的变量(靠 model.dict() 或 model.model_dump())。
复杂点在于字段可选性语义不一致:TypedDict 的 NotRequired 表示“键可不存在”,而 Pydantic 的 Field(default=None) 表示“键存在但值为 None”——两边对齐需要额外逻辑判断。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











