JSONからPython TypedDictへの変換

dict構文を変更せずに型安全なディクショナリアクセスを提供するPython TypedDictにJSONを変換する方法を学びます。total、NotRequired、ReadOnlyを解説します。

Pydantic & TypedDict

詳細な説明

JSONからTypedDictへ

TypedDict(typing から)は、dictインターフェースを変更せずにディクショナリに型アノテーションを追加できます。dataclassとは異なり、TypedDictの値はブラケット記法(d["key"])でアクセスします。

JSONの例

{
  "id": 1,
  "name": "Alice",
  "email": "alice@example.com",
  "role": "admin"
}

生成されるPython

from typing import TypedDict

class User(TypedDict):
    id: int
    name: str
    email: str
    role: str

使用方法

import json

data: User = json.loads(raw_json)
print(data["name"])  # "Alice" — 型チェッカーはこれがstrであることを認識

TypedDict vs dataclass

機能 TypedDict dataclass
アクセス構文 d["key"] d.key
ランタイム型 dict カスタムクラス
json.loads() 互換 はい(直接) いいえ(構築が必要)
インスタンスメソッド なし あり
バリデーション なし なし(またはPydantic)

NotRequiredによるオプショナルキー

from typing import TypedDict, NotRequired

class User(TypedDict):
    id: int
    name: str
    bio: NotRequired[str]  # 不在の場合がある

total vs partial

デフォルトでは、すべてのキーが必須です(total=True)。total=False に設定するとすべてのキーがオプショナルになります:

class PartialUser(TypedDict, total=False):
    id: int
    name: str
    email: str

ReadOnly(Python 3.13+)

from typing import ReadOnly

class Config(TypedDict):
    version: ReadOnly[str]
    debug: bool

TypedDictを選ぶべき場面

  • 属性アクセスではなくdict型アクセスdata["key"])が必要。
  • 既存のdictベースコードに型安全性を追加したいが、リファクタリングはしたくない。
  • データが直接 json.loads() から来ており、オーバーヘッドゼロの型チェックが必要。
  • プレーンなdictを返すサードパーティAPIにアノテーションを追加したい。

ネストされたTypedDict

class Address(TypedDict):
    street: str
    city: str

class User(TypedDict):
    name: str
    address: Address

ネストされた値は実行時にはプレーンなdictのままですが、型チェッカーは形状を強制します。

ユースケース

JSONパースしたdictをあらゆる場所で渡す既存コードベースに型安全性を追加しており、すべての関数をdataclassインスタンスを受け取るようにリファクタリングせずにmypyカバレッジが欲しい場合に使用します。

試してみる — JSON to Python Converter

フルツールを開く