SEJATIDIMEDIA Logo
Tersedia Sesi Konsultasi Gratis
SejatiDimedia Logo

Type Inference, Kapan TypeScript Udah Cukup Pinter dan Kapan Perlu Dibantu

Banyak pemula yang kebiasaan nulis anotasi tipe di mana-mana padahal TypeScript sebenarnya udah bisa nebak sendiri. Artikel ini ngebahas gimana mekanisme type inference kerja di balik layar, kapan inference bekerja dengan baik, dan kapan justru bisa menyesatkan, misalnya di array kosong atau objek yang bentuknya berubah seiring waktu. Ada juga pembahasan soal contextual typing dan kapan sebaiknya tetap nulis anotasi eksplisit meski secara teknis gak wajib. Cocok buat kamu yang ngerasa kode TypeScript-nya kepanjangan gara-gara kebanyakan nulis tipe manual.

Timur Dian Radha Sejati

Timur Dian Radha Sejati

Founder SejatiDimedia•25 September 2026•5 menit baca
Silabus Seri Rekayasa

TypeScript Fundamentals

Series ini dirancang untuk membangun fondasi TypeScript yang kuat bagi pembaca yang baru mulai belajar atau ingin memperkuat pemahaman dasarnya. Dimulai dari alasan mendasar kenapa TypeScript layak dipelajari dibanding JavaScript murni, lanjut ke konsep-konsep inti seperti perbedaan any, unknown, dan never, cara kerja type inference, union dan intersection type, generics, hingga utility types yang paling sering dipakai di proyek nyata. Setiap artikel ditulis dengan pendekatan step by step, disertai contoh kode dan studi kasus dunia nyata, sehingga pembaca tidak hanya tahu "apa" tapi juga paham "kenapa" di balik setiap konsep. Series ini menjadi pondasi sebelum masuk ke topik yang lebih advance seperti type level programming dan pola arsitektur TypeScript di Series berikutnya.

Lihat Silabus Lengkap
Type Inference, Kapan TypeScript Udah Cukup Pinter dan Kapan Perlu Dibantu

Coba perhatiin dua potongan kode ini:

index.tstypescript
1
let umur: number = 25;
2
let nama: string = "Budi";
2 baris•49 chars
UTF-8•Spaces: 4

vs

index.tstypescript
1
let umur = 25;
2
let nama = "Budi";
2 baris•33 chars
UTF-8•Spaces: 4

Keduanya sama-sama valid di TypeScript, dan keduanya sama-sama aman. Bedanya, versi kedua gak perlu nulis anotasi tipe sama sekali, tapi TypeScript tetap tahu

PLAINTEXT Snippetplaintext
1
umur
1 baris•4 chars
UTF-8•Spaces: 4
itu
PLAINTEXT Snippetplaintext
1
number
1 baris•6 chars
UTF-8•Spaces: 4
dan
PLAINTEXT Snippetplaintext
1
nama
1 baris•4 chars
UTF-8•Spaces: 4
itu
PLAINTEXT Snippetplaintext
1
string
1 baris•6 chars
UTF-8•Spaces: 4
. Ini yang disebut type inference, kemampuan TypeScript buat nebak tipe data sendiri berdasarkan nilai yang kamu kasih.

Banyak pemula yang belum ngeh soal ini, akhirnya kebiasaan nulis anotasi tipe di semua tempat, padahal banyak yang sebenarnya gak perlu. Efeknya, kode jadi lebih panjang dari yang seharusnya, dan malah kelihatan lebih ribet dibanding manfaatnya.

Gimana Sebenarnya Type Inference Bekerja

TypeScript nebak tipe data dari beberapa sumber, tergantung konteksnya. Yang paling gampang adalah dari nilai literal yang kamu tulis langsung.

index.tstypescript
1
let harga = 50000; // TypeScript tahu ini number
2
let aktif = true; // TypeScript tahu ini boolean
3
let daftarNama = ["Andi", "Budi"]; // TypeScript tahu ini string[]
3 baris•164 chars
UTF-8•Spaces: 4

Selain dari nilai literal, TypeScript juga bisa nebak tipe dari return value sebuah fungsi, tanpa kamu perlu nulis tipe return-nya secara eksplisit.

index.tstypescript
1
function tambah(a: number, b: number) {
2
return a + b;
3
}
4
// TypeScript otomatis tahu return type-nya number
4 baris•108 chars
UTF-8•Spaces: 4

Yang menarik, meskipun kamu gak nulis

PLAINTEXT Snippetplaintext
1
: number
1 baris•8 chars
UTF-8•Spaces: 4
setelah parameter closing di atas, TypeScript tetap bisa nebak dengan benar karena dia ngeliat tipe dari
PLAINTEXT Snippetplaintext
1
a
1 baris•1 chars
UTF-8•Spaces: 4
dan
PLAINTEXT Snippetplaintext
1
b
1 baris•1 chars
UTF-8•Spaces: 4
, terus ngikutin gimana operasi
PLAINTEXT Snippetplaintext
1
+
1 baris•1 chars
UTF-8•Spaces: 4
bekerja di antara dua
PLAINTEXT Snippetplaintext
1
number
1 baris•6 chars
UTF-8•Spaces: 4
.

Contextual Typing, Nebak Tipe dari "Situasi Sekitar"

Selain nebak dari nilai langsung, TypeScript juga punya kemampuan yang disebut contextual typing, yaitu nebak tipe berdasarkan konteks di mana kode itu dipakai, bukan cuma dari nilainya sendiri.

Contoh paling gampang ada di event handler:

index.tstypescript
1
window.addEventListener("click", function (event) {
2
console.log(event.button); // TypeScript tahu event itu MouseEvent
3
});
3 baris•124 chars
UTF-8•Spaces: 4

Perhatiin, kamu gak nulis tipe apa-apa buat parameter

PLAINTEXT Snippetplaintext
1
event
1 baris•5 chars
UTF-8•Spaces: 4
, tapi TypeScript tetap tahu itu
PLAINTEXT Snippetplaintext
1
MouseEvent
1 baris•10 chars
UTF-8•Spaces: 4
, lengkap dengan semua propertinya kayak
PLAINTEXT Snippetplaintext
1
button
1 baris•6 chars
UTF-8•Spaces: 4
,
PLAINTEXT Snippetplaintext
1
clientX
1 baris•7 chars
UTF-8•Spaces: 4
, dan seterusnya. Ini kejadian karena TypeScript udah tahu signature dari
PLAINTEXT Snippetplaintext
1
addEventListener
1 baris•16 chars
UTF-8•Spaces: 4
, dan dia "nurunin" tipe yang sesuai ke parameter fungsi callback kamu berdasarkan konteks itu.

Ini juga kejadian pas kamu kerja sama array method kayak

PLAINTEXT Snippetplaintext
1
map
1 baris•3 chars
UTF-8•Spaces: 4
atau
PLAINTEXT Snippetplaintext
1
filter
1 baris•6 chars
UTF-8•Spaces: 4
.

index.tstypescript
1
const angka = [1, 2, 3];
2
const kuadrat = angka.map((n) => n * n);
3
// TypeScript tahu n itu number, tanpa perlu ditulis manual
3 baris•125 chars
UTF-8•Spaces: 4

Kapan Inference Bisa Menyesatkan

Type inference emang membantu banget, tapi bukan berarti dia selalu sempurna. Ada beberapa kasus umum di mana inference justru bisa bikin bug yang gak kelihatan di awal.

Array Kosong

index.tstypescript
1
let daftar = [];
2
daftar.push("a");
3
daftar.push(1);
3 baris•50 chars
UTF-8•Spaces: 4

Coba tebak, tipe apa yang TypeScript kasih ke

PLAINTEXT Snippetplaintext
1
daftar
1 baris•6 chars
UTF-8•Spaces: 4
di baris pertama? Karena array-nya kosong, TypeScript gak punya cukup informasi buat nebak isinya bakal berupa apa, jadi dia kasih tipe
PLAINTEXT Snippetplaintext
1
any[]
1 baris•5 chars
UTF-8•Spaces: 4
. Ini artinya,
PLAINTEXT Snippetplaintext
1
daftar.push("a")
1 baris•16 chars
UTF-8•Spaces: 4
dan
PLAINTEXT Snippetplaintext
1
daftar.push(1)
1 baris•14 chars
UTF-8•Spaces: 4
sama-sama gak akan dianggap error, padahal mungkin maksud kamu awalnya cuma buat nampung angka aja.

Solusinya, kasih anotasi eksplisit dari awal kalau kamu udah tahu isinya bakal apa:

index.tstypescript
1
let daftar: number[] = [];
2
daftar.push(1); // aman
3
daftar.push("a"); // Error, string gak bisa masuk ke number[]
3 baris•112 chars
UTF-8•Spaces: 4

Objek yang Bentuknya Berubah Seiring Waktu

index.tstypescript
1
let user = { nama: "Andi" };
2
user.umur = 25; // Error, properti umur gak ada di tipe awal
2 baris•89 chars
UTF-8•Spaces: 4

Ini sering bikin bingung pemula. Kenapa error padahal cuma nambahin properti baru? Jawabannya, pas kamu nulis

PLAINTEXT Snippetplaintext
1
let user = { nama: "Andi" }
1 baris•27 chars
UTF-8•Spaces: 4
, TypeScript langsung nebak tipe
PLAINTEXT Snippetplaintext
1
user
1 baris•4 chars
UTF-8•Spaces: 4
itu
PLAINTEXT Snippetplaintext
1
{ nama: string }
1 baris•16 chars
UTF-8•Spaces: 4
, dan tipe ini "dikunci" dari awal. TypeScript gak otomatis ngizinin kamu nambahin properti baru setelahnya, karena secara default dia nganggep bentuk objek itu tetap dari awal sampai akhir.

Solusinya, definisiin bentuk lengkap dari awal, entah lewat interface atau langsung di deklarasi:

index.tstypescript
1
interface User {
2
nama: string;
3
umur?: number;
4
}
5
 
6
let user: User = { nama: "Andi" };
7
user.umur = 25; // aman
7 baris•111 chars
UTF-8•Spaces: 4

Best Common Type yang Kadang Terlalu Luas

Kalau kamu bikin array yang isinya campuran beberapa tipe, TypeScript bakal nyari "best common type", alias tipe gabungan yang paling masuk akal buat nampung semuanya.

index.tstypescript
1
let campuran = [1, "dua", true];
2
// TypeScript nebak tipe: (string | number | boolean)[]
2 baris•88 chars
UTF-8•Spaces: 4

Ini sebenarnya udah bener secara teknis, tapi kadang terlalu luas buat kebutuhan kamu. Kalau kamu sebenarnya cuma pengen array angka aja dan yang lain itu kesalahan input, inference kayak gini justru bisa nutupin bug yang sebenarnya harusnya ketahuan dari awal.

Jadi, Kapan Sebaiknya Tetap Nulis Anotasi Manual?

Aturan umumnya, biarin TypeScript nebak sendiri kalau nilainya udah jelas dan gak ambigu, kayak variabel lokal dengan nilai langsung, atau return value fungsi yang sederhana. Tapi ada beberapa situasi di mana nulis anotasi eksplisit tetap lebih baik, meskipun secara teknis gak wajib.

Parameter fungsi, karena TypeScript gak bisa nebak tipe parameter dari mana pun kalau kamu gak kasih tahu:

index.tstypescript
1
function sapa(nama) {
2
// Error di strict mode, parameter 'nama' implisit any
3
return `Halo, ${nama}`;
4
}
4 baris•106 chars
UTF-8•Spaces: 4

Return type fungsi publik yang dipakai di banyak tempat, biar ada "kontrak" yang jelas dan gak berubah tanpa sengaja pas kamu refactor isi fungsinya.

Array atau objek kosong yang bakal diisi belakangan, kayak contoh

PLAINTEXT Snippetplaintext
1
daftar: number[] = []
1 baris•21 chars
UTF-8•Spaces: 4
di atas.

Variabel yang emang sengaja fleksibel di awal, misalnya state di komponen UI yang awalnya

PLAINTEXT Snippetplaintext
1
null
1 baris•4 chars
UTF-8•Spaces: 4
tapi nanti bisa jadi objek tertentu.

index.tstypescript
1
let selectedUser: User | null = null;
1 baris•37 chars
UTF-8•Spaces: 4

Kalau kamu gak kasih anotasi di kasus terakhir ini, TypeScript bakal nganggep

PLAINTEXT Snippetplaintext
1
selectedUser
1 baris•12 chars
UTF-8•Spaces: 4
selamanya bertipe
PLAINTEXT Snippetplaintext
1
null
1 baris•4 chars
UTF-8•Spaces: 4
, dan kamu gak bakal bisa assign objek
PLAINTEXT Snippetplaintext
1
User
1 baris•4 chars
UTF-8•Spaces: 4
ke variabel itu nanti.

Kesimpulan

Type inference itu salah satu fitur yang bikin TypeScript kerasa gak seribet yang dibayangin orang pas pertama kali denger "bahasa dengan tipe statis". Kamu gak perlu nulis tipe di setiap baris, karena TypeScript udah cukup pinter buat nebak sendiri di banyak kasus. Tapi penting buat tahu di titik mana inference bisa menyesatkan, kayak array kosong, objek yang bentuknya berubah, atau best common type yang kelewat luas, biar kamu tahu kapan harus turun tangan dan nulis anotasi manual.

Di artikel selanjutnya, kita bakal masuk ke union, intersection, dan discriminated union, salah satu fitur paling kuat di TypeScript buat memodelkan data yang punya banyak kemungkinan bentuk, kayak state loading, success, dan error di aplikasi nyata.

Topik Terkait:JavascriptTypescfript
Timur Dian Radha Sejati

Timur Dian Radha Sejati

Penulis & Lead Engineer

Software engineer dan konsultan sistem di SejatiDimedia. Berfokus pada perancangan arsitektur berkinerja tinggi, refactoring backend skala enterprise, hingga pengembangan aplikasi mobile, web modern dan integrasi AI.

Punya Masalah Arsitektur atau Ingin Membangun Sistem yang Benar?

Kami siap membantu mengaudit kode, me-refactor arsitektur yang lemot, atau membangun aplikasi bisnis Anda dengan standar enterprise sejak awal.

EKSPLORASI LANJUTAN

Artikel Rekayasa Terkait

Lihat Semua
Utility Types yang Wajib Diketahui Setiap Developer TypeScript
Best Practices
5 menit baca

Utility Types yang Wajib Diketahui Setiap Developer TypeScript

Artikel penutup Series 1 ini ngebahas kumpulan utility types bawaan TypeScript yang paling sering dipake di proyek nyata, kayak `Partial`, `Required`, `Pick`, `Omit`, `Record`, dan `ReturnType`. Setiap utility type dijelasin lewat use case konkret, misalnya `Partial` buat bikin form update yang field-nya opsional, `Omit` buat bikin DTO dari model database, dan `Record` buat bikin mapping objek yang type safe. Di akhir artikel ada juga pengenalan singkat cara bikin utility type sendiri, sebagai jembatan menuju Series 2 yang bahas type level programming lebih dalam.

Baca Artikel
Generics, dari Dasar sampai Constraint
Best Practices
5 menit baca

Generics, dari Dasar sampai Constraint

Generics sering dianggap topik yang menakutkan buat pemula, padahal konsepnya sederhana banget kalau dijelasin pake analogi yang pas. Artikel ini mulai dari masalah nyata yang diselesain generics, yaitu bikin fungsi atau komponen yang reusable tanpa kehilangan informasi tipe. Pembaca bakal diajak bangun pemahaman step by step, dari generic function sederhana, generic interface, sampai penggunaan `extends` buat batasin tipe apa aja yang boleh masuk, dan default type parameter biar generic lebih fleksibel. Semua dijelasin pake contoh kode dunia nyata kayak fungsi fetch data API dan komponen wrapper.

Baca Artikel
Union, Intersection, dan Discriminated Union, Cara Memodelkan Data yang Punya Banyak Kemungkinan Bentuk
Best Practices
5 menit baca

Union, Intersection, dan Discriminated Union, Cara Memodelkan Data yang Punya Banyak Kemungkinan Bentuk

Artikel ini fokus ke salah satu fitur paling kuat di TypeScript buat memodelkan data yang bentuknya bisa berubah-ubah. Dimulai dari union type dasar buat bilang "nilai ini bisa A atau B", lanjut ke intersection type buat gabungin beberapa tipe jadi satu, sampai discriminated union yang super berguna buat memodelkan state kayak loading, success, dan error di aplikasi nyata. Ada juga pembahasan gimana TypeScript otomatis ngelakuin narrowing berdasarkan properti pembeda, jadi kode kamu lebih aman tanpa perlu banyak pengecekan manual yang rawan salah.

Baca Artikel