Kenapa ini penting
Function adalah tempat bug paling sering lahir: argumen tertukar urutannya, lupa mengirim parameter, atau mengembalikan undefined di salah satu cabang if. Di JavaScript, hitungDiskon(harga, persen) dan hitungDiskon(persen, harga) sama-sama "jalan". Di TypeScript, tipe parameter adalah kontrak: siapa pun yang memanggil function harus memenuhi kontrak itu, dan function sendiri wajib menepati janjinya soal nilai kembalian.
Bayangkan mesin fotokopi di kantor. Di bagian atasnya ada tulisan "Masukkan kertas A4, maksimal 50 lembar, hasilnya salinan A4". Itu kontrak. Kalau kamu memasukkan kardus, mesin menolak sebelum macet. Tipe parameter dan return adalah tulisan di mesin fotokopi itu, dan karena kontraknya tertulis, editor bisa menunjukkan kontrak tersebut setiap kali kamu mengetik nama function.
Konsep inti
Parameter dan return type
function hitungDiskon(harga: number, persen: number): number {
return harga - (harga * persen) / 100;
}
Tipe parameter wajib ditulis (di mode strict, parameter tanpa tipe dianggap any implisit dan menghasilkan error TS7006). Tipe kembalian bisa ditebak oleh TypeScript, tapi menuliskannya untuk function yang diekspor membuat niatmu jelas dan menangkap bug di dalam function, misalnya cabang yang lupa return.
Arrow function dan function expression
const kali = (a: number, b: number): number => a * b;
// Tipe function ditulis terpisah, lalu dipakai
type Operasi = (a: number, b: number) => number;
const bagi: Operasi = (a, b) => a / b; // a dan b otomatis number
Perhatikan baris terakhir: karena bagi sudah diberi tipe Operasi, parameter a dan b tidak perlu dianotasi lagi. Ini disebut contextual typing, dan inilah sebabnya callback di .map() atau onClick jarang perlu tipe eksplisit.
Parameter opsional dan default
- Parameter opsional ditandai
?dan bertipeT | undefineddi dalam function. Harus diletakkan setelah parameter wajib. - Parameter dengan nilai default otomatis opsional bagi pemanggil, dan tipenya ditebak dari nilai default.
function sapa(nama: string, gelar?: string): string {
return gelar ? `Halo, ${gelar} ${nama}` : `Halo, ${nama}`;
}
function formatRupiah(angka: number, denganSimbol = true): string {
const teks = angka.toLocaleString("id-ID");
return denganSimbol ? `Rp${teks}` : teks;
}
Rest parameter
function jumlahkan(...angka: number[]): number {
return angka.reduce((a, b) => a + b, 0);
}
Parameter object (destructuring)
Kalau parameter lebih dari tiga, lebih aman pakai satu object. Urutan tidak bisa tertukar dan pemanggilan lebih mudah dibaca:
type OpsiPesan = { tujuan: string; isi: string; penting?: boolean };
function kirimPesan({ tujuan, isi, penting = false }: OpsiPesan): void {
console.log(`${penting ? "[!] " : ""}Ke ${tujuan}: ${isi}`);
}
Callback type
Function yang menerima function lain perlu menjelaskan bentuk callback-nya:
function ulangi(kali: number, aksi: (ke: number) => void): void {
for (let i = 1; i <= kali; i++) aksi(i);
}
Tipe kembalian void pada callback punya arti khusus: "nilai kembaliannya tidak akan dipakai". Karena itu ulangi(3, (i) => daftar.push(i)) tetap boleh walaupun push mengembalikan angka.
Function overload
Kadang satu function menerima beberapa bentuk input dan tipe kembaliannya bergantung pada input. Overload menuliskan beberapa "tanda tangan" (signature) di atas satu implementasi:
function ubah(nilai: string): number;
function ubah(nilai: number): string;
function ubah(nilai: string | number): string | number {
return typeof nilai === "string" ? Number(nilai) : String(nilai);
}
Pemanggil hanya melihat dua signature pertama. Implementasinya (yang ketiga) tidak terlihat dari luar. Overload berguna tapi jangan berlebihan; sering kali union atau generics (modul Generics) lebih sederhana.
Function async
Function async selalu mengembalikan Promise. Return type-nya ditulis Promise<T>, di mana T adalah nilai yang kamu return di dalamnya:
async function ambilJumlahPesanan(tokoId: number): Promise<number> {
const daftar = [3, 5, 2]; // anggap hasil dari server untuk toko ini
return daftar.length + tokoId * 0;
}
ambilJumlahPesanan(1).then((n) => console.log(n.toFixed(0))); // → 3
Kalau kamu lupa await dan memperlakukan hasilnya seperti angka biasa, misalnya ambilJumlahPesanan(1) + 1, TypeScript menolak karena Promise<number> bukan number. Ini menangkap salah satu bug async paling umum, yaitu lupa await, jauh sebelum aplikasi berjalan.
Membaca signature di editor
Salah satu manfaat terbesar function bertipe adalah dokumentasi gratis. Saat kamu mengetik hitungDiskon(, editor menampilkan hitungDiskon(harga: number, persen: number): number. Kamu tidak perlu membuka file aslinya untuk tahu urutan argumen. Biasakan memberi nama parameter yang jelas (persen, bukan p), karena nama itulah yang muncul di petunjuk editor. Untuk penjelasan tambahan, tulis komentar JSDoc /** ... */ di atas function; editor juga menampilkannya saat hover.
void vs undefined sebagai return
void artinya "jangan andalkan nilai kembaliannya". undefined artinya "function ini benar-benar mengembalikan undefined". Untuk function biasa tanpa return, pakai void.
Contoh kode
// kasir.ts, function bertipe untuk aplikasi kasir sederhana
type Item = { nama: string; harga: number; jumlah: number };
// 1. Parameter + return eksplisit
function subtotal(item: Item): number {
return item.harga * item.jumlah;
}
// 2. Parameter opsional + default
function hitungTotal(items: Item[], diskonPersen = 0, kodeVoucher?: string): number {
let total = items.reduce((acc, item) => acc + subtotal(item), 0);
total -= (total * diskonPersen) / 100;
if (kodeVoucher === "HEMAT10K") total -= 10000;
return Math.max(total, 0);
}
// 3. Callback type
function cetakStruk(items: Item[], format: (angka: number) => string): void {
for (const item of items) {
console.log(`${item.nama} x${item.jumlah} = ${format(subtotal(item))}`);
}
}
const rupiah = (angka: number): string => `Rp${angka.toLocaleString("id-ID")}`;
const belanja: Item[] = [
{ nama: "Kopi", harga: 25000, jumlah: 2 },
{ nama: "Donat", harga: 12000, jumlah: 3 },
];
cetakStruk(belanja, rupiah);
// → Kopi x2 = Rp50.000
// → Donat x3 = Rp36.000
console.log(rupiah(hitungTotal(belanja))); // → Rp86.000
console.log(rupiah(hitungTotal(belanja, 10))); // → Rp77.400
console.log(rupiah(hitungTotal(belanja, 0, "HEMAT10K"))); // → Rp76.000
// 4. Kesalahan yang ditangkap TypeScript
hitungTotal(belanja, "10"); // ❌ error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
cetakStruk(belanja); // ❌ error TS2554: Expected 2 arguments, but got 1.
Contoh overload dan bahaya lupa return:
// overload.ts
function ambilElemen(id: string): HTMLElement | null;
function ambilElemen(ids: string[]): (HTMLElement | null)[];
function ambilElemen(input: string | string[]): HTMLElement | null | (HTMLElement | null)[] {
if (Array.isArray(input)) return input.map((id) => document.getElementById(id));
return document.getElementById(input);
}
const satu = ambilElemen("judul"); // tipe: HTMLElement | null
const banyak = ambilElemen(["judul", "isi"]); // tipe: (HTMLElement | null)[]
console.log(satu, banyak.length);
// Lupa return di salah satu cabang
function kategoriUmur(umur: number): string { // ❌ error TS2366: Function lacks ending return statement and return type does not include 'undefined'.
if (umur < 13) return "anak";
if (umur < 18) return "remaja";
}
Error terakhir hanya muncul karena kita menulis : string sebagai return type. Tanpa anotasi itu, TypeScript diam-diam menyimpulkan string | undefined dan bug baru ketahuan saat ada yang memanggil kategoriUmur(30).toUpperCase().
Kesalahan umum
- Tidak memberi tipe pada parameter. Di mode strict hasilnya error
TS7006: Parameter 'x' implicitly has an 'any' type.Selalu beri tipe parameter, kecuali callback yang sudah mendapat contextual typing. - Meletakkan parameter opsional sebelum yang wajib.
function f(a?: string, b: number)adalah error. Pindahkan yang opsional ke belakang, atau pakai parameter object. - Memakai
Functionsebagai tipe callback.Functionmenerima function apa saja tanpa info parameter. Tulis bentuknya:(id: number) => void. - Tidak menulis return type di function publik. Bug "lupa return di satu cabang" lolos. Untuk function yang diekspor, tulis return type.
- Overload untuk segala hal. Kalau tipe kembalian tidak bergantung pada input, cukup pakai union sederhana. Overload menambah kerumitan yang harus dirawat.
Latihan
- Mudah, Tulis
luasLingkaran(jari: number): numberdankelilingLingkaransebagai arrow function dengan tipetype Rumus = (jari: number) => number. - Sedang, Tulis
buatSlug(judul: string, pemisah = "-"): stringyang mengubah"Belajar TypeScript Dasar"menjadi"belajar-typescript-dasar". Lalu tulisfilterAngka(angka: number[], syarat: (n: number) => boolean): number[]. - Menantang, Tulis function dengan overload
format(nilai: number): string(format rupiah) danformat(nilai: Date): string(format tanggal Indonesia, misalnya24 Oktober 2026).
Lihat solusi
// 1. Mudah
function luasLingkaran(jari: number): number {
return Math.PI * jari ** 2;
}
type Rumus = (jari: number) => number;
const kelilingLingkaran: Rumus = (jari) => 2 * Math.PI * jari;
console.log(luasLingkaran(7).toFixed(2), kelilingLingkaran(7).toFixed(2)); // → 153.94 43.98
// 2. Sedang
function buatSlug(judul: string, pemisah = "-"): string {
return judul.trim().toLowerCase().split(/\s+/).join(pemisah);
}
console.log(buatSlug("Belajar TypeScript Dasar")); // → belajar-typescript-dasar
function filterAngka(angka: number[], syarat: (n: number) => boolean): number[] {
return angka.filter(syarat);
}
console.log(filterAngka([1, 2, 3, 4, 5, 6], (n) => n % 2 === 0)); // → [ 2, 4, 6 ]
// 3. Menantang
function format(nilai: number): string;
function format(nilai: Date): string;
function format(nilai: number | Date): string {
if (nilai instanceof Date) {
return nilai.toLocaleDateString("id-ID", { day: "numeric", month: "long", year: "numeric" });
}
return `Rp${nilai.toLocaleString("id-ID")}`;
}
console.log(format(150000)); // → Rp150.000
console.log(format(new Date(2026, 9, 24))); // → 24 Oktober 2026
Ringkasan
- Tipe parameter wajib ditulis; return type sebaiknya ditulis untuk function publik agar bug di dalam function tertangkap.
?membuat parameter opsional (T | undefined), nilai default membuat parameter opsional sekaligus memberi tipe.- Tipe function ditulis
(a: A) => R; variabel atau callback yang sudah bertipe tidak perlu anotasi ulang (contextual typing). - Overload memberi beberapa signature untuk satu implementasi ketika tipe kembalian bergantung pada input.
- Lebih dari tiga parameter? Pakai satu parameter object agar urutan tidak tertukar.