Fungsi memanggil fungsi lain dan dipanggil oleh bagian lain dari program, sehingga kontrak tipenya perlu dinyatakan dengan jelas. Topik ini membahas pengetikan parameter dan nilai kembalian, perbedaan tipe void dan never, serta overload untuk fungsi dengan tanda tangan berganda. Setelah membacanya, fungsi dapat ditulis dengan kontrak tipe yang utuh dari sisi pemanggil maupun sisi implementasinya.
Tanda tangan fungsi: parameter dan kembalian#
Tanda tangan fungsi (function signature) terdiri atas tipe setiap parameter dan tipe nilai kembaliannya. Anotasi tipe ditulis setelah nama parameter, sedangkan tipe kembalian ditulis setelah daftar parameter dan sebelum badan fungsi. Kombinasi keduanya menjadi kontrak yang diperiksa compiler pada definisi maupun pada setiap pemanggilan.
function rataRata(daftar: number[]): number {
const total = daftar.reduce((jumlah, nilai) => jumlah + nilai, 0);
return total / daftar.length;
}
const rata: number = rataRata([80, 90, 100]);
console.log(rata);
console.log(rata.toFixed(1));90
90.0Dengan tanda tangan yang lengkap, pemeriksaan berjalan dua arah sekaligus. Argumen yang tidak sesuai ditolak pada titik pemanggilan, sedangkan nilai kembalian dari badan fungsi wajib cocok dengan tipe kembalian yang dinyatakan. Bila tipe kembalian tidak ditulis, compiler tetap menyimpulkannya dari return, tetapi anotasi eksplisit membuat kontrak fungsi terbaca tanpa perlu membaca badannya.
Parameter juga boleh ditandai opsional dengan tanda tanya, misalnya gelar?: string, sehingga argumennya boleh tidak diberikan dan tipenya menjadi string | undefined. Parameter dengan nilai bawaan seperti skor = 0 diperlakukan setara dengan parameter opsional. Parameter opsional, parameter dengan nilai bawaan, dan rest parameter, yaitu parameter berawalan ... yang menampung sisa argumen, wajib diletakkan setelah parameter wajib, sehingga urutan argumen tetap dapat ditentukan compiler.
Kembalian void untuk fungsi tanpa nilai#
Tipe void menyatakan bahwa nilai kembalian fungsi tidak dimaksudkan untuk dipakai pemanggil. Fungsi yang mencetak salam, menulis log, atau mengubah keadaan program biasanya bertipe kembalian void. Karena kontraknya tidak menjanjikan nilai, hasil pemanggilannya tidak boleh ditampung ke variabel.
function cetakSalam(nama: string): void {
console.log(`Selamat datang, ${nama}.`);
}
function simpanLog(pesan: string): void {
console.log(`[log] ${pesan}`);
}
cetakSalam("Dewi");
simpanLog("layanan dimulai");Selamat datang, Dewi.
[log] layanan dimulaiBerkas berikut menunjukkan percobaan menampung hasil pemanggilan void, dan compiler menolaknya.
// tidak-dijalankan
function cetakSalam(nama: string): void {
console.log(`Selamat datang, ${nama}.`);
}
const angka: number = cetakSalam("Dewi");
console.log(angka);# berkas ini sengaja tidak lolos pemeriksaan tipe
tsc --noEmit hasil-void.tshasil-void.ts(6,7): error TS2322: Type 'void' is not assignable to type 'number'.Pesan error di atas menegaskan bahwa void bukan undefined. Tipe void berarti nilai kembalian memang tidak diperhitungkan, sedangkan fungsi yang bertipe kembalian undefined tetap mengembalikan nilai yang sah untuk ditampung. Karena itu, hasil pemanggilan void yang ditampung ditolak compiler, meskipun pada saat runtime tidak ada nilai yang dikembalikan.
Tipe void juga sering muncul pada tipe callback, yaitu fungsi yang diserahkan untuk dipanggil oleh kode lain, misalnya () => void untuk fungsi yang dipanggil tanpa memperdulikan hasilnya. Pada situasi ini aturannya berbalik, karena fungsi yang sesungguhnya mengembalikan nilai tetap boleh dipakai pada posisi callback bertipe void. Alasannya, pemanggil callback sudah berjanji tidak menggunakan hasil tersebut, sehingga nilai yang dikembalikan tidak menimbulkan masalah.
Kembalian never untuk fungsi yang tak pernah selesai#
Tipe never menyatakan fungsi yang tidak pernah kembali ke pemanggil secara normal. Dua pola yang menghasilkan never adalah fungsi yang selalu melempar error dan fungsi yang perulangannya tidak pernah berakhir. Tipe ini berbeda dari void, karena fungsi void tetap selesai dan kembali, hanya tanpa nilai.
function gagalParsel(barisan: string): never {
throw new Error(`Barisan tidak sah: ${barisan}`);
}
function ambilSkor(teks: string): number {
const skor = Number(teks);
if (Number.isNaN(skor)) {
return gagalParsel(teks);
}
return skor;
}
try {
ambilSkor("sembilan puluh");
} catch (error) {
console.log(`tertangkap: ${(error as Error).message}`);
}
console.log(ambilSkor("90"));tertangkap: Barisan tidak sah: sembilan puluh
90Pada contoh, fungsi ambilSkor boleh mengembalikan gagalParsel di dalam percabangan tanpa melanggar tipe kembaliannya. Aturan pemeriksaan membolehkan ekspresi bertipe never diletakkan pada posisi tipe apa pun, sehingga jalur kembalian yang sah tidak terganggu oleh jalur yang selalu gagal. Compiler juga memahami bahwa eksekusi tidak akan pernah mencapai baris setelah pemanggilan fungsi bertipe never.
Dari sisi teori tipe, never adalah tipe tanpa anggota, sehingga tidak ada satu nilai pun yang bertipe never. Sifat itulah yang membuatnya berguna sebagai penanda alur eksekusi yang tidak terjangkau, dan irisan tipe yang saling bertentangan pun jatuh ke never. Sifat yang sama menjadi dasar pemeriksaan ekshaustif, yaitu penugasan sisa union ke never yang gagal kompilasi bila masih ada anggota yang tertinggal.
Overload untuk tanda tangan berganda#
Overload adalah daftar beberapa tanda tangan untuk satu fungsi yang sama. Mekanisme ini digunakan ketika satu fungsi menerima kombinasi argumen yang berbeda dan pola kembaliannya ikut berbeda. Tanda tangan overload ditulis berturut-turut tanpa badan, sedangkan satu implementasi menampung seluruh variasinya, dan pemanggil hanya melihat tanda tangan overload.
function jumlahkan(a: number, b: number): number;
function jumlahkan(a: string, b: string): string;
function jumlahkan(a: number | string, b: number | string): number | string {
if (typeof a === "number" && typeof b === "number") {
return a + b;
}
return `${a}${b}`;
}
console.log(jumlahkan(2, 3));
console.log(jumlahkan("tiket", "-01"));5
tiket-01// tidak-dijalankan
function jumlahkan(a: number, b: number): number;
function jumlahkan(a: string, b: string): string;
function jumlahkan(a: number | string, b: number | string): number | string {
if (typeof a === "number" && typeof b === "number") {
return a + b;
}
return `${a}${b}`;
}
console.log(jumlahkan(2, "tiga"));# berkas ini sengaja tidak lolos pemeriksaan tipe
tsc --noEmit overload-salah.tsoverload-salah.ts(11,23): error TS2769: No overload matches this call.
The last overload gave the following error.
Argument of type 'number' is not assignable to parameter of type 'string'.Pesan error menunjukkan sifat penting overload, yaitu kombinasi argumen harus cocok dengan salah satu tanda tangan secara utuh. Pemanggilan dengan satu number dan satu string tidak cocok dengan tanda tangan mana pun, meskipun parameter union pada implementasinya secara teknis membolehkannya. Larangan semacam ini memang disengaja, karena implementasi tidak menjanjikan perilaku untuk kombinasi argumen campuran.
Kesalahan umum#
Kekeliruan pertama adalah memilih never untuk fungsi yang selesai tanpa nilai. Fungsi bertipe never menandakan jalur eksekusi berhenti total, sehingga compiler akan menganggap kode setelah pemanggilannya tidak terjangkau, padahal fungsi yang dimaksud sebenarnya kembali normal. Perbaikannya adalah menggunakan void untuk fungsi yang selesai tanpa nilai dan menyisihkan never untuk fungsi yang selalu melempar error atau tidak pernah berakhir.
Kekeliruan kedua adalah mendeklarasikan overload padahal union pada parameter sudah cukup. Bila perilaku fungsi sama untuk semua jenis argumennya, satu tanda tangan dengan parameter union lebih ringkas dan lebih mudah dipelihara daripada dua tanda tangan overload yang berbagi satu badan implementasi. Panduan resmi menyarankan menulis overload hanya ketika pola kembaliannya benar-benar berbeda, dan memilih parameter union untuk kasus yang seragam.
Kekeliruan ketiga adalah mencoba memanggil fungsi overload dengan tipe union yang hanya dimiliki implementasinya. Tanda tangan implementasi tidak terlihat oleh pemanggil, sehingga pemanggilan yang tidak cocok dengan tanda tangan overload mana pun selalu ditolak meskipun parameternya bertipe union. Perbaikannya adalah memanggil sesuai salah satu tanda tangan yang tersedia, atau menambahkan tanda tangan baru apabila pola pemanggilan itu memang sah.
Ringkasan#
- Tanda tangan fungsi memuat tipe parameter dan tipe kembalian, dan keduanya diperiksa compiler pada definisi maupun pemanggilan.
voidberarti nilai kembalian tidak diperhitungkan dan tidak boleh ditampung, sedangkanneverberarti fungsi tidak pernah kembali secara normal.- Overload menyediakan beberapa tanda tangan untuk satu implementasi, dan setiap pemanggilan wajib cocok dengan salah satu tanda tangan secara utuh.
- Tanda tangan implementasi tidak terlihat oleh pemanggil, sehingga tidak dapat dipanggil secara langsung.
Referensi#
- Functions — The TypeScript Handbook — Membahas return type void, never, dan function overloads beserta panduan menulisnya.