Sepanjang Section ini kita berkali-kali menulis “checker membaca kode tanpa menjalankannya”. Pernyataan tersebut layak dibedah dengan serius, karena dari situlah segala kekuatan dan segala batasan static type checking berasal: apa yang bisa diketahui sebelum eksekusi, apa yang baru terungkap saat eksekusi, dan bagaimana sebaiknya kita mengadopsinya pada project nyata. Pemahaman ini juga mencegah ekspektasi keliru — checker bukan alat pembasmi bug, melainkan alat pembasmi kelas bug tertentu.
Arti Kata Statis #
Static type checker adalah pembaca kode yang sangat teliti: mypy atau Pyright mengurai setiap berkas, membangun peta semua assignment dan pemanggilan, lalu mencari kontradiksi anotasi — semuanya tanpa mengeksekusi satu baris pun program. Konsekuensinya dua arah. Ke arah baik: pemeriksaan berjalan lengkap atas seluruh codebase, termasuk cabang if yang hari ini belum pernah dijalankan. Ke arah terbatas: checker tidak pernah tahu nilai apa yang sesungguhnya mengalir — variabel harga bisa saja berisi 0 atau -5000, dan itu bukan urusan checker.
Kontrasnya, uji runtime — menjalankan program atau pytest — melakukan kebalikannya: nilai-nilai nyata dievaluasi, tetapi hanya jalur yang benar-benar dilalui yang terperiksa.
Apa yang Ditangkap Checker #
Kelas galat yang menjadi makanan pokok checker berkaitan dengan bentuk program. Simpan sebagai produk.py:
class Produk:
def __init__(self, nama: str) -> None:
self.nama = nama
produk = Produk("Kopi")
print(produk.harga)python3 -m mypy produk.pyOutput yang Dihasilkan:
produk.py:6: error: "Produk" has no attribute "harga" [attr-defined]
Found 1 error in 1 file (checked 1 source file)Atribut harga memang tidak pernah didefinisikan — di runtime, baris ini pasti menaikkan AttributeError. Checker menangkapnya lebih awal tanpa menjalankan program. Daftar tangkapan tipikal sejenis:
- attribute yang tidak ada (
produk.hargadi atas) dan salah ketik nama method - argument bertipe salah pada function beranotasi (
sapa(42)dari Chapter Pengenalan Type Hints) Noneyang tidak ditangani pada nilai balikX | None- assignment yang mengganti tipe variabel secara tidak konsisten
Apa yang Hanya Muncul Saat Runtime #
Nilai bukan wilayah checker. Simpan sebagai pembagian.py:
def bagi(a: int, b: int) -> int:
return a // b
print(bagi(10, 2))
print(bagi(10, 0))Checker memberi nilai bersih:
python3 -m mypy pembagian.pyOutput yang Dihasilkan:
Success: no issues found in 1 source fileNamun saat program benar-benar dijalankan:
python3 pembagian.pyOutput yang Dihasilkan:
5
Traceback (most recent call last):
File "pembagian.py", line 5, in <module>
print(bagi(10, 0))
^^^^^^^^^^^
File "pembagian.py", line 2, in bagi
return a // b
~~^^~~
ZeroDivisionError: integer division or modulo by zeroBagi checker, a // b dengan dua integer adalah operasi yang sah secara tipe — bahwa b berisi nol adalah fakta nilai yang baru ada saat pemanggilan berlangsung. Demikian pula file yang hilang, response API yang berubah, dan input pengguna yang aneh: semua adalah urusan runtime. Inilah alasan static checking tidak menggantikan testing — keduanya memburu hewan yang berbeda.
Batas Soundness #
Sebuah checker disebut sound bila tidak pernah meloloskan kode yang salah. Checker Python tidak sepenuhnya sound, dan kadang suara laporan “Success” lebih optimistis dari kenyataan. Simpan sebagai kamus.py:
def ambil_nilai(data: dict[str, int]) -> int:
return data["kunci"] # checker percaya kunci pasti ada
data_kosong: dict[str, int] = {}
print(ambil_nilai(data_kosong))python3 -m mypy kamus.pyOutput yang Dihasilkan:
Success: no issues found in 1 source fileSementara itu, python3 kamus.py menaikkan KeyError: 'kunci'. Anotasi dict[str, int] tidak berisi janji bahwa key "kunci" terisi — checker memilih memercayai pemakaian [...] daripada membanjiri kita laporan “key mungkin tidak ada” di setiap baris. Batas-batas pragmatis semacam ini, ditambah keberadaan Any dan kode tanpa anotasi, berarti: laporan bersih menaikkan keyakinan, bukan jaminan.
Strategi Adopsi Bertahap #
| Tahap | Tindakan | Dampak |
|---|---|---|
| 1 | Jalankan checker bawaan (tanpa config) pada project lama | Galat paling jelas muncul; tidak ada perubahan kode |
| 2 | Anotasi function publik dan titik batas data | Salah tipe dari luar tertangkap di gerbang |
| 3 | Rapikan laporan bertahap, mulai dari error paling banyak | Laporan menurun, disiplin terbangun |
| 4 | Naikkan ketegasan lewat config (--strict atau pyproject.toml) | Pemeriksaan penuh untuk kode baru |
Dengan pemahaman ini, kita siap mengoperasikan checkernya sendiri secara praktis — lewat mypy di terminal dan Pyright di editor — pada chapter penutup Section ini.