Data JSON dan hasil query database lazim hadir sebagai dictionary dengan bentuk tetap: key yang sama, tipe value yang sudah diketahui. Anotasi dict[str, int] tidak bisa menggambarkan kontrak semacam ini — anotasi itu hanya bicara “semua value bertipe int”, padahal bentuk nyatanya lebih kaya: nama selalu string, harga selalu integer, tag berupa list. TypedDict dari module typing mengisi kekosongan ini: sebuah definisi bernama untuk bentuk dictionary, lengkap dengan tipe per key.
Mendefinisikan dan Menggunakan TypedDict #
Definisi TypedDict ditulis seperti class, tetapi setiap atributnya adalah anotasi key:
from typing import TypedDict
class MenuToko(TypedDict):
nama: str
harga: int
menu: MenuToko = {"nama": "Kopi Susu", "harga": 18000}
print(menu["nama"], menu["harga"])
print(isinstance(menu, dict))Output yang Dihasilkan:
Kopi Susu 18000
TrueMari kita telaah baris-barisnya:
- Baris 3-5 (
class MenuToko):namadanhargabukan atribut object — keduanya adalah kontrak key. Di runtime,MenuTokoberubah menjadi dictionary biasa. - Baris 7 (
menu: MenuToko = {...}): isi dictionary diperiksa terhadap kontrak — key harus lengkap, dan setiap value harus cocok tipenya. - Baris 9 (
isinstance(menu, dict)): mengonfirmasi hakikat runtime-nya —True, karenamenumemang dictionary; TypedDict tidak membuat class baru yang berjalan.
Checker memperlakukan menu["nama"] bertipe str dan menu["harga"] bertipe int — melanggar salah satunya langsung tertangkap. Simpan sebagai menu.py:
from typing import TypedDict
class MenuToko(TypedDict):
nama: str
harga: int
menu: MenuToko = {"nama": "Kopi Susu", "harga": "delapan ribu"}python3 -m mypy menu.pyOutput yang Dihasilkan:
menu.py:7: error: Incompatible types (expression has type "str", TypedDict item "harga" has type "int") [typeddict-item]
Found 1 error in 1 file (checked 1 source file)total=False untuk Key Opsional #
Secara bawaan (total=True), semua key wajib ada. Untuk key yang boleh absen, definisikan TypedDict dengan total=False:
from typing import TypedDict
class ProfilPengguna(TypedDict, total=False):
nama: str
kota: str
profil: ProfilPengguna = {"nama": "Budi"}
print(profil)
profil["kota"] = "Bandung"
print(profil)Output yang Dihasilkan:
{'nama': 'Budi'}
{'nama': 'Budi', 'kota': 'Bandung'}Karena kota opsional, dictionary yang hanya berisi nama langsung sah. Akses key opsional tetap perlu hati-hati: menurut checker, profil["kota"] berstatus str (checker mempercayai key tersebut ada), sedangkan profil.get("kota") berstatus str | None — jujur terhadap kemungkinan key belum diisi. Di runtime, profil["kota"] menaikkan KeyError bila key-nya memang belum pernah diisi, jadi gunakan .get() ketika absennya key wajar terjadi.
TypedDict Bersarang #
Value dari sebuah key bisa berupa TypedDict lain — cara alami memodelkan JSON bertingkat:
from typing import TypedDict
class Alamat(TypedDict):
kota: str
kode_pos: str
class Pengguna(TypedDict):
nama: str
alamat: Alamat
pengguna: Pengguna = {
"nama": "Siti",
"alamat": {"kota": "Bandung", "kode_pos": "40115"},
}
print(pengguna["alamat"]["kota"])Output yang Dihasilkan:
BandungAkses bertingkat pengguna["alamat"]["kota"] ikut terperiksa: checker tahu pengguna["alamat"] bertipe Alamat, sehingga "kota" sah dan bertipe str, sedangkan key yang tidak dikenal akan ditolak.
TypedDict atau Dataclass? #
Keduanya memodelkan struktur data bernama, tetapi hakikat runtime-nya berbeda total:
| Aspek | TypedDict | Dataclass |
|---|---|---|
| Wujud runtime | dictionary biasa | object dengan atribut |
| Cara akses | menu["harga"] | produk.harga |
| Konversi dari/ke JSON | langsung (json.dumps) | perlu asdict() |
| Method dan perilaku | tidak ada (murni data) | bisa punya method |
| Pemeriksaan runtime | tidak ada | tidak ada (sama-sama statis) |
Aturan praktisnya: jika data keluar-masuk dunia luar sebagai dictionary — response API, baris csv.DictReader, hasil json.loads — TypedDict membiarkan data tetap dictionary tanpa lapisan konversi. Jika data punya perilaku atau akan diproses sebagai object, dataclass lebih tepat; kita telah membahasnya pada Chapter Dataclasses di Section Advanced Data Modeling.