Episode ini membahas contract-driven development: menurunkan tipe dari skema dengan openapi-typescript, tipe dari Prisma, dan validasi runtime dengan Zod. Kalian akan memahami kenapa tipe hasil generate lebih unggul daripada tipe yang ditulis tangan.

Salah satu sumber bug paling besar di aplikasi modern adalah ketidakcocokan bentuk data antara frontend dan backend. Tipe yang ditulis tangan di dua tempat akan berpisah seiring waktu. Contract-driven development menyelesaikannya: satu sumber kebenaran, tipe diturunkan dari sana.
Gagasannya sederhana. Kalian mendefinisikan kontrak data sekali, lalu alat generate membuat tipe TypeScript dari kontrak itu. Backend dan frontend memakai tipe yang sama persis, lahir dari skema yang sama, sehingga tidak ada yang bisa melenceng.
Episode 17 membahas tiga alat populer dalam pola ini: openapi-typescript untuk API REST, Prisma untuk database, dan Zod untuk validasi runtime. Kalian akan melihat kenapa tipe hasil generate lebih dipercaya daripada yang ditulis manual.
Pola ini mengganti definisi tipe manual dengan skema:
bunx openapi-typescript schema.json -o types/api.d.tsPerintah bunx openapi-typescript membaca spesifikasi OpenAPI dan menghasilkan file deklarasi tipe. Setiap endpoint, request body, dan respons berubah menjadi tipe TypeScript. Bila backend mengubah skema, tipe di-frontend diperbarui dengan menjalankan perintah generate kembali.
Tipe manual bisa ketinggalan, salah salin, atau ditulis setengah. Tipe hasil generate selalu mencerminkan skema terbaru. Itulah sebabnya contract-driven development semakin populer: sinkronisasi tidak bergantung pada disiplin developer, tapi pada proses yang otomatis.
Hasil generate memberi tipe untuk setiap endpoint:
import type { components } from "./types/api";
type Pengguna = components["schemas"]["Pengguna"];
async function ambilPengguna(id: number): Promise<Pengguna> {
const respons = await fetch(`/users/${id}`);
const data = await respons.json();
return data as Pengguna;
}Deklarasi import type { components } mengambil tipe dari file generate. components["schemas"]["Pengguna"] menunjuk skema Pengguna yang didefinisikan backend. Frontend memakai bentuk yang dijamin sama dengan apa yang akan dikirim backend.
Prisma menurunkan tipe dari skema database:
model Pengguna {
id Int @id @default(autoincrement())
nama String
}Dari skema di atas, Prisma menghasilkan tipe dan operasi database yang terketik penuh. Query yang salah bentuk properti langsung ditolak compiler:
const hasil = await prisma.pengguna.findMany({
where: { nama: { contains: "Budi" } },
select: { id: true, nama: true },
});Tipe hasil diturunkan dari select, jadi kalian hanya bisa mengakses id dan nama. Prisma menjadikan database sebagai sumber kebenaran kedua dalam ekosistem tipe aplikasi.
Tipe compiler hilang saat runtime. Zod mengembalikannya dengan validasi:
bun add zodimport { z } from "zod";
const SkemaLogin = z.object({
email: z.string().email(),
password: z.string().min(8),
});
type InputLogin = z.infer<typeof SkemaLogin>;
const dataAman: InputLogin = SkemaLogin.parse(dataDariClient);Skema SkemaLogin memvalidasi data saat runtime: email harus valid, password minimal delapan karakter. Operator z.infer menurunkan tipe TypeScript dari skema secara otomatis. Zod menjaga kontrak di jalur data yang paling berbahaya: input dari luar.
Pola yang paling matang menggabungkan semua alat di atas:
Info
Urutan yang dianjurkan: Prisma atau skema lain sebagai sumber model domain, OpenAPI untuk kontrak HTTP antar layanan, dan Zod di setiap titik masuk data dari luar. Tipe dari ketiganya dipertemukan di satu folder types agar satu perubahan menyebar konsisten.
Ketika skema berubah, langkahnya selalu sama: perbarui skema, jalankan generate, dan biarkan compiler menunjuk setiap kode yang perlu menyesuaikan. Kompilasi menjadi jaringan keamanan yang menjaga frontend dan backend tetap seirama.
Episode 17 mengubah cara kalian memandang tipe: bukan lagi tulisan tangan yang mudah melenceng, melainkan hasil generate dari skema. Contract-driven development membuat kontrak antar sistem terjaga oleh proses, bukan oleh ingatan.
Inti yang harus dibawa pulang:
openapi-typescript menurunkan tipe dari spesifikasi OpenAPI.z.infer.Di episode 18 selanjutnya kita akan membahas testing, linting, dan editor support untuk TypeScript, yaitu menegakkan kualitas kode dengan alat yang memahami sistem tipe.