โ† Semua pembelajaran / Astro Nol โ†’ Portal Berita
Fase 0 ยท Fondasi: Node, TypeScript & Cara Pikir Astro

TypeScript secukupnya untuk Astro

Kamu tidak perlu menguasai TypeScript untuk memakai Astro. Kamu perlu enam konstruksi, dan disiplin untuk tidak menulis any.

Sumber asli docs.astro.build Resmi Rangkuman ~8 menit baca

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 strict sejak awal. Melonggarkannya nanti mudah; mengetatkannya di proyek 200 berkas hampir tidak pernah terjadi.
  • astro check yang memeriksa berkas .astro โ€” tsc saja tidak melihatnya.
  • Astro.props diberi tipe lewat interface 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"]
}
PresetIsinyaPakai kalau
baseNyaris tanpa pengecekan ketatTidak pernah, untuk proyek baru
strictstrictNullChecks, noImplicitAny, dan kawan-kawannyaDefault yang benar
strictestDitambah noUncheckedIndexedAccess dan sejenisnyaKalau 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.