TypeScript secukupnya untuk Astro
Kamu tidak perlu menguasai TypeScript untuk memakai Astro. Kamu perlu enam konstruksi, dan disiplin untuk tidak menulis any.
Intisari
- Astro memakai TypeScript untuk pengecekan, bukan untuk runtime โ tipe dihapus saat build dan tidak pernah memvalidasi data dari luar.
- Itu konsekuensi terpenting: tipe tidak menjaga data dari database maupun API. Untuk itu ada Zod (Fase 3).
- Pakai preset
strictsejak awal. Melonggarkannya nanti mudah; mengetatkannya di proyek 200 berkas hampir tidak pernah terjadi. astro checkyang memeriksa berkas.astroโtscsaja tidak melihatnya.Astro.propsdiberi tipe lewatinterface Props, dan itu yang membuat komponen punya kontrak.
Yang perlu dipahami lebih dulu dari sintaksnya
TypeScript dihapus seluruhnya saat build. Tidak ada satu pun anotasi tipe yang tersisa di kode yang berjalan. Konsekuensinya keras dan sering dilupakan orang yang datang dari PHP 8 dengan typed properties:
interface Artikel {
id: number;
judul: string;
terbitPada: Date;
}
// Ini KEBOHONGAN yang dipercaya compiler sampai runtime.
const artikel = await res.json() as Artikel;
console.log(artikel.terbitPada.getFullYear());
// TypeError: artikel.terbitPada.getFullYear is not a function
// JSON tidak punya tipe Date. Isinya string.
Compiler senang, program mati. as bukan konversi โ ia perintah untuk berhenti memeriksa.
Aturan yang kupakai sepanjang roadmap ini: as hanya boleh dipakai kalau kamu sendiri
yang membuat nilainya sesaat sebelumnya. Untuk data yang datang dari database, API, form, atau
cookie, gunakan validasi runtime.
Enam konstruksi yang benar-benar dipakai
1. Anotasi dasar dan inferensi
const judul: string = "Rupiah menguat"; // eksplisit, sering tidak perlu
const jumlah = 42; // TypeScript sudah tahu: number
const tags: string[] = []; // ini perlu โ array kosong tidak bisa disimpulkan
Jangan menganotasi apa yang sudah bisa disimpulkan. Anotasi berlebihan membuat kode lebih berisik tanpa menambah keamanan, dan justru menyulitkan saat tipe sumbernya berubah.
2. interface untuk bentuk objek
interface Artikel {
id: number;
judul: string;
ringkasan: string | null; // boleh null โ dan compiler akan memaksamu mengeceknya
premium: boolean;
terbitPada: Date;
}
string | null itu union type, dan di mode strict ia menular: kamu tidak bisa
memanggil .length pada ringkasan sebelum membuktikan ia bukan null. Ini bukan
gangguan โ ini persis kelas bug yang paling sering terjadi di portal berita, di mana kolom lama sering
NULL untuk artikel yang dibuat sebelum fiturnya ada.
3. Union literal โ pengganti enum untuk status
type StatusArtikel = "draf" | "tinjau" | "terbit" | "arsip";
function bisaDilihatPublik(s: StatusArtikel): boolean {
return s === "terbit";
}
bisaDilihatPublik("published");
// Error: Argument of type '"published"' is not assignable to
// parameter of type 'StatusArtikel'.
Ini konstruksi paling menguntungkan saat migrasi dari CI3. Di CI3 status artikel adalah string bebas yang
dicek dengan if ($row->status == 'publish') di tiga puluh tempat, dan salah ketik di satu
tempat baru ketahuan di produksi. Di sini editor kodemu menolaknya sebelum kamu sempat menyimpan berkas.
4. Optional dan default
interface Props {
judul: string;
level?: 1 | 2 | 3; // boleh tidak diisi
}
const { judul, level = 2 } = Astro.props;
5. Generic, sebatas membacanya
Kamu jarang perlu menulis generic di Astro, tapi akan sering membacanya โ terutama di Kysely, yang seluruh keamanannya berdiri di atas generic:
const db = new Kysely<DB>({ dialect });
// ^^^^
// "Kysely yang tahu skema bernama DB". Dari sinilah autocomplete
// nama tabel dan nama kolom itu datang.
6. satisfies โ yang paling berguna dan paling jarang diajarkan
const konfigCache = {
artikel: { ttl: 300, tag: "artikel" },
beranda: { ttl: 60, tag: "beranda" },
} satisfies Record<string, { ttl: number; tag: string }>;
konfigCache.artikel.ttl; // number โ tipe aslinya dipertahankan
konfigCache.majalah; // Error: property 'majalah' does not exist
Bedanya dengan : Record<...> biasa: dengan anotasi, TypeScript melupakan kunci mana
saja yang benar-benar ada dan konfigCache.majalah lolos. Dengan satisfies, ia
memeriksa bentuknya dan mengingat isinya. Untuk tabel konfigurasi โ peta rute, peta cache tag,
daftar tier membership โ ini selalu pilihan yang benar.
Memberi tipe pada komponen Astro
---
interface Props {
artikel: Artikel;
tampilkanRingkasan?: boolean;
}
const { artikel, tampilkanRingkasan = true } = Astro.props;
---
<article>
<h2>{artikel.judul}</h2>
{tampilkanRingkasan && artikel.ringkasan && <p>{artikel.ringkasan}</p>}
</article>
Nama Props itu istimewa โ Astro mencarinya secara khusus. Setelah interface ini ada, memanggil
<KartuArtikel /> tanpa prop artikel jadi error saat astro check,
bukan halaman kosong saat produksi.
Perhatikan juga artikel.ringkasan && di baris terakhir. Karena tipenya
string | null, mode strict memaksa pengecekan itu. Tanpanya kamu akan merender
<p>null</p> โ persis bug yang muncul di halaman arsip berita lama.
Konfigurasi yang dipakai
{
"extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"]
}
| Preset | Isinya | Pakai kalau |
|---|---|---|
base | Nyaris tanpa pengecekan ketat | Tidak pernah, untuk proyek baru |
strict | strictNullChecks, noImplicitAny, dan kawan-kawannya | Default yang benar |
strictest | Ditambah noUncheckedIndexedAccess dan sejenisnya | Kalau timmu sudah nyaman dengan TypeScript |
astro check, bukan tsc. tsc tidak tahu cara membaca
berkas .astro โ ia akan melaporkan "sukses" sambil melewatkan seluruh komponenmu.
Jalankan pnpm astro check di CI, dan jadikan kegagalannya memblokir merge. Ini pagar
paling murah yang bisa kamu pasang di proyek ini.
Latihan: tulis src/types/artikel.ts berisi interface Artikel dan
type StatusArtikel yang mencerminkan tabel artikel CI3-mu yang sebenarnya โ termasuk kolom
yang boleh NULL. Lalu buat komponen KartuArtikel.astro dengan
interface Props, panggil dari sebuah halaman tanpa mengirim prop yang
wajib, dan jalankan pnpm astro check. Pastikan ia gagal โ dan baca pesan errornya sampai
habis.
Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.