Fungsi adalah komponen terpenting dalam setiap program, dan TypeScript memberikan kekuatan penuh untuk membuatnya lebih aman. Jika di JavaScript kamu bisa memanggil fungsi dengan argumen yang salah tanpa peringatan, TypeScript menangkap semua kesalahan itu sebelum kode dijalankan. Di artikel ini kita akan mempelajari cara menambahkan tipe pada semua aspek fungsi TypeScript.
Tipe Parameter dan Return Value
// Syntax: (param: tipe): returnType => { ... }
function sapa(nama: string, umur: number): string {
return `Halo, ${nama}! Kamu berumur ${umur} tahun.`;
}
const pesan = sapa("Rina", 22);
console.log(pesan);
// Output: Halo, Rina! Kamu berumur 22 tahun.
// Kesalahan yang langsung terdeteksi
sapa(22, "Rina"); // ❌ Error: argumen terbalik
sapa("Rina"); // ❌ Error: kurang argumen
sapa("Rina", 22, "ekstra"); // ❌ Error: terlalu banyak argumen
Fungsi void
// void: fungsi yang tidak mengembalikan nilai
function log_pesan(pesan: string, level: "info" | "error" | "warn"): void {
const timestamp = new Date().toISOString();
console.log(`[${timestamp}] [${level.toUpperCase()}] ${pesan}`);
}
log_pesan("Server dimulai", "info");
// Output: [2026-04-05T...] [INFO] Server dimulai
log_pesan("Koneksi gagal", "error");
// Output: [2026-04-05T...] [ERROR] Koneksi gagal
Arrow Function dengan Tipe
// Arrow function dengan tipe eksplisit
const tambah = (a: number, b: number): number => a + b;
// Tipe fungsi bisa dideklarasikan terpisah
const kurang: (a: number, b: number) => number = (a, b) => a - b;
// Tipe fungsi yang disimpan dalam variabel
const format_harga: (harga: number) => string = (harga) => {
return `Rp ${harga.toLocaleString("id-ID")}`;
};
console.log(tambah(10, 5)); // Output: 15
console.log(kurang(10, 5)); // Output: 5
console.log(format_harga(150_000)); // Output: Rp 150.000
Parameter Optional dan Default
Parameter Optional dengan ?
// Parameter opsional harus di akhir
function buat_profil(nama: string, umur: number, kota?: string): string {
if (kota) {
return `${nama} (${umur}) dari ${kota}`;
}
return `${nama} (${umur})`;
}
console.log(buat_profil("Ali", 25, "Jakarta"));
// Output: Ali (25) dari Jakarta
console.log(buat_profil("Budi", 30));
// Output: Budi (30)
Parameter Default
function hitung_pajak(harga: number, persen: number = 11): number {
return harga * persen / 100;
}
console.log(hitung_pajak(1_000_000)); // Output: 110000 (menggunakan default 11%)
console.log(hitung_pajak(1_000_000, 5)); // Output: 50000
// Contoh lebih kompleks
function buat_url(
path: string,
base: string = "https://api.kamusngoding.com",
version: string = "v1"
): string {
return `${base}/${version}/${path}`;
}
console.log(buat_url("users"));
// Output: https://api.kamusngoding.com/v1/users
console.log(buat_url("products", "https://api.toko.com", "v2"));
// Output: https://api.toko.com/v2/products
Rest Parameters dengan Tipe
// Menerima jumlah argumen tidak terbatas
function jumlahkan(label: string, ...angka: number[]): string {
const total = angka.reduce((sum, n) => sum + n, 0);
return `${label}: ${total}`;
}
console.log(jumlahkan("Total belanja", 50_000, 120_000, 75_000));
// Output: Total belanja: 245000
console.log(jumlahkan("Nilai siswa", 85, 92, 78, 95, 88));
// Output: Nilai siswa: 438
// Dengan spread operator
const nilai = [80, 90, 70];
console.log(jumlahkan("Rata rata", ...nilai));
// Output: Rata rata: 240
Function Overloads
TypeScript memungkinkan mendefinisikan beberapa “signature” untuk satu fungsi:
// Deklarasi overload (tanpa implementasi)
function parse_id(id: string): { tipe: "string"; nilai: string };
function parse_id(id: number): { tipe: "number"; nilai: string };
// Implementasi (harus kompatibel dengan semua overload)
function parse_id(id: string | number): { tipe: "string" | "number"; nilai: string } {
if (typeof id === "string") {
return { tipe: "string", nilai: id.toUpperCase() };
}
return { tipe: "number", nilai: id.toString().padStart(6, "0") };
}
const a = parse_id("usr-123");
console.log(a); // Output: { tipe: 'string', nilai: 'USR-123' }
const b = parse_id(42);
console.log(b); // Output: { tipe: 'number', nilai: '000042' }
Mengetik Callback dan Higher-Order Function
// Mendefinisikan tipe callback
type KallbackTransformasi = (nilai: number) => number;
function terapkan_transformasi(angka: number[], callback: KallbackTransformasi): number[] {
return angka.map(callback);
}
const hasil = terapkan_transformasi([1, 2, 3, 4, 5], (n) => n * n);
console.log(hasil);
// Output: [1, 4, 9, 16, 25]
// Filter dengan typed callback
type Predikat<T> = (item: T) => boolean;
function saring<T>(items: T[], predikat: Predikat<T>): T[] {
return items.filter(predikat);
}
const angka = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const genap = saring(angka, (n) => n % 2 === 0);
console.log(genap);
// Output: [2, 4, 6, 8, 10]
const nama_nama = ["Ali", "Budi", "Candra", "Dewi", "Eko"];
const huruf_a = saring(nama_nama, (n) => n.startsWith("A") || n.startsWith("C"));
console.log(huruf_a);
// Output: ['Ali', 'Candra']
Tipe Fungsi sebagai Variabel
// Mendefinisikan tipe fungsi
type OperasiMatematika = (a: number, b: number) => number;
const tambah: OperasiMatematika = (a, b) => a + b;
const kurang: OperasiMatematika = (a, b) => a - b;
const kali: OperasiMatematika = (a, b) => a * b;
// Fungsi sebagai argumen
function hitung(a: number, b: number, operasi: OperasiMatematika): number {
return operasi(a, b);
}
console.log(hitung(10, 3, tambah)); // Output: 13
console.log(hitung(10, 3, kurang)); // Output: 7
console.log(hitung(10, 3, kali)); // Output: 30
// Menyimpan dalam objek (seperti "kalkulator")
const operasi_tersedia: { [key: string]: OperasiMatematika } = {
"+": tambah,
"-": kurang,
"*": kali,
"/": (a, b) => b !== 0 ? a / b : 0
};
console.log(operasi_tersedia["+"](15, 7)); // Output: 22
console.log(operasi_tersedia["*"](4, 6)); // Output: 24
Pertanyaan yang Sering Diajukan
Kapan harus menulis return type secara eksplisit?
TypeScript bisa menyimpulkan return type, tapi ada kasus di mana penulisan eksplisit lebih baik: (1) fungsi yang kompleks atau panjang agar niat lebih jelas, (2) fungsi yang diekspor dari modul sebagai bagian API, (3) saat return type void perlu ditegaskan. Untuk fungsi sederhana, biarkan TypeScript yang menyimpulkan.
Apa perbedaan parameter ? dan parameter dengan nilai default?
param?: string berarti parameter bisa tidak diisi dan nilainya akan undefined. param: string = "default" berarti parameter bisa tidak diisi tapi nilainya akan "default". Gunakan nilai default jika kamu punya nilai fallback yang masuk akal; gunakan ? jika kamu perlu mendeteksi apakah parameter benar-benar diberikan atau tidak.
Apakah function overloads diperlukan untuk pemula?
Tidak wajib di awal. Overloads berguna untuk library atau API yang mengekspos fungsi dengan perilaku berbeda berdasarkan tipe input. Untuk kode aplikasi biasa, union type pada parameter sudah cukup. Tapi memahami overloads penting karena banyak library JavaScript populer menggunakannya.
Mengapa generic <T> digunakan dalam contoh saring()?
Generic memungkinkan fungsi bekerja dengan berbagai tipe data sekaligus tetap type-safe. saring<T> bekerja untuk T = number, T = string, atau tipe lainnya tanpa kehilangan informasi tipe. Ini akan dipelajari lebih dalam di artikel TypeScript tentang Generics.
Kesimpulan
Ringkasan cara mengetik fungsi di TypeScript:
| Fitur | Sintaks | Contoh |
|---|---|---|
| Parameter + return | (p: T): R | (n: number): string |
| void return | : void | Tidak ada return |
| Optional param | param?: T | nama?: string |
| Default param | param: T = val | n: number = 0 |
| Rest params | ...params: T[] | ...angka: number[] |
| Tipe fungsi | (p: T) => R | (a: number) => string |
| Overloads | Multiple signatures | Lihat contoh di atas |
Artikel sebelumnya: Tipe Data Dasar di TypeScript — semua tipe dasar TypeScript.
Langkah selanjutnya: Interface dan Type Alias di TypeScript — cara mendefinisikan struktur objek yang reusable dan type-safe.