TypeScript Practical Typing untuk Produk Nyata
Cara ngetik data API, form state, dan mapping database biar minim bug tanpa bikin developer jadi lambat. Tips TypeScript dari pengalaman bikin produk beneran.
DaunsCode Editorial Team
admin@daunscode.com • 14 Feb 2026
TypeScript Itu Buat Apa Sih?
Oke jadi kalau kamu udah familiar sama JavaScript, TypeScript itu basically JavaScript tapi dengan type system. Jadi kamu bisa tentuin "variabel ini harus string", "fungsi ini return number", "object ini harus punya property x dan y".
Kenapa penting? Karena di project yang makin gede, tanpa type system itu kayak jalan di gelap gelapan. Kamu nggak tau data yang masuk bentuknya apa, property apa aja yang available, dan error baru ketauan pas runtime (alias pas user udah pake).
Dengan TypeScript, error ketauan pas nulis kode. Jauh lebih murah fix bug di editor daripada di production kan?
Typing Data dari API
Ini case paling umum. Kamu fetch data dari API dan perlu tau shape datanya.
// Definisiin type berdasarkan response API
type Article = {
id: string;
slug: string;
title: string;
excerpt: string;
content: string;
category: string;
tags: string[];
status: "draft" | "published" | "archived";
readingMinutes: number;
coverImageUrl: string | null;
publishedAt: string;
createdAt: string;
};
// Sekarang TypeScript tau persis bentuk datanya
async function getArticle(slug: string): Promise<Article | null> {
const { data } = await supabase
.from("articles")
.select("*")
.eq("slug", slug)
.single();
return data;
}
Dengan type ini, kalau kamu typo nulis article.tittle (harusnya title), TypeScript langsung kasih tau error. Nggak perlu nunggu runtime.
Union Type buat Status
Perhatiin tipe status di atas: "draft" | "published" | "archived". Ini namanya union type.
Kenapa nggak pakai string aja? Karena dengan union type, TypeScript bisa:
- Autocomplete option yang valid
- Error kalau kamu assign value yang nggak valid
- Exhaustive check di switch case
function getStatusColor(status: Article["status"]) {
switch (status) {
case "draft":
return "yellow";
case "published":
return "green";
case "archived":
return "gray";
// TypeScript bakal warning kalau ada case yang belum di-handle
}
}
Typing Form State
Form itu sumber bug terbanyak di frontend. Dengan TypeScript, kamu bisa bikin form yang type safe:
type ArticleForm = {
title: string;
slug: string;
excerpt: string;
content: string;
category: string;
tags: string[];
coverImage: File | null;
};
const [form, setForm] = useState<ArticleForm>({
title: "",
slug: "",
excerpt: "",
content: "",
category: "",
tags: [],
coverImage: null,
});
// TypeScript tau persis property apa yang bisa di-update
function updateField<K extends keyof ArticleForm>(
key: K,
value: ArticleForm[K]
) {
setForm((prev) => ({ ...prev, [key]: value }));
}
// Ini valid
updateField("title", "Hello");
// Ini error, tags harusnya string[] bukan string
updateField("tags", "wrong");
Generic constraint K extends keyof ArticleForm bikin TypeScript tau bahwa value harus sesuai sama type dari key nya. Powerful banget.
Mapping Database ke Frontend
Database biasanya pake snake_case, frontend pake camelCase. Kita perlu mapping yang type safe:
// Type dari database (snake_case)
type ArticleRow = {
id: string;
slug: string;
title: string;
cover_image_url: string | null;
reading_minutes: number;
published_at: string;
created_at: string;
};
// Type buat frontend (camelCase)
type Article = {
id: string;
slug: string;
title: string;
coverImageUrl: string | null;
readingMinutes: number;
publishedAt: string;
createdAt: string;
};
// Mapper function
function mapArticle(row: ArticleRow): Article {
return {
id: row.id,
slug: row.slug,
title: row.title,
coverImageUrl: row.cover_image_url,
readingMinutes: row.reading_minutes,
publishedAt: row.published_at,
createdAt: row.created_at,
};
}
Dengan mapper ini, kalau schema database berubah (misal nambah kolom), TypeScript bakal kasih error di mapper function. Jadi kamu nggak lupa update frontend nya.
Utility Types yang Sering Dipake
TypeScript punya built in utility types yang super berguna:
// Partial bikin semua property jadi optional
type ArticleUpdate = Partial<Article>;
// Pick ambil beberapa property aja
type ArticleCard = Pick<Article, "slug" | "title" | "excerpt" | "coverImageUrl">;
// Omit buang beberapa property
type ArticleCreate = Omit<Article, "id" | "createdAt">;
// Record bikin object type
type StatusLabel = Record<Article["status"], string>;
const labels: StatusLabel = {
draft: "Draf",
published: "Terbit",
archived: "Diarsipkan",
};
Dengan utility types, kamu nggak perlu bikin type baru dari scratch. Cukup derive dari type yang udah ada.
Jangan Over Type
Satu hal yang penting: jangan kebanyakan typing sampai bikin development jadi lambat. Beberapa prinsip:
- Type inference itu teman kalau TypeScript udah bisa infer type nya, nggak perlu annotate manual
- any itu boleh (kadang kadang) kalau lagi prototyping atau dealing sama third party yang type nya nggak jelas, pakai any dulu trus refine nanti
- Fokus ke boundary type yang paling penting itu di boundary: API response, function parameter, component props
- Jangan bikin type yang terlalu generic kalau type nya cuma dipake di satu tempat, nggak perlu bikin super generic
Kesimpulan
TypeScript itu investasi yang worth it buat projek yang serius. Bisa nangkep bug lebih awal, bikin refactoring lebih aman, dan editor jadi jauh lebih helpful.
Tapi inget, TypeScript itu alat, bukan tujuan. Gunain sesuai kebutuhan, jangan sampe malah jadi bottleneck development. Yang penting: type di boundary, inference di internal, dan consistent di seluruh codebase.
Ready to build the next big thing?
DaunsCode siap bantu arsitektur, UI, dan implementasi produk digital yang scalable untuk bisnis kamu.
Let's Talk Project