Masukkan Password
57 Fungsi Overloading
Kita bahas Function Overloading di TypeScript dari nol, karena konsep ini memang agak membingungkan kalau baru pertama kali melihatnya.
Inti masalahnya sebenarnya sederhana:
Function Overloading digunakan ketika satu nama function bisa menerima beberapa kombinasi tipe parameter, dan kita ingin TypeScript tahu return type yang tepat untuk setiap kombinasi tersebut.
1. Mulai dari masalahnya
Di lecture ada function:
type StringOrNumber = string | number;
function addition(a: StringOrNumber, b: StringOrNumber) {
if (typeof a === "string" || typeof b === "string") {
return a.toString() + b.toString();
}
return a + b;
}
Function ini bisa menerima:
addition(10, 20);
atau:
addition("Hello", "World");
atau:
addition(10, "Hello");
atau:
addition("Hello", 10);
Karena parameter-nya:
a: string | number
b: string | number
2. Function ini sebenarnya punya beberapa kemungkinan
Kalau kita lihat kombinasi inputnya:
a | b | Hasil |
|---|---|---|
number | number | number |
string | string | string |
number | string | string |
string | number | string |
Contohnya:
addition(10, 20);
hasil:
30
yaitu number.
Sedangkan:
addition("Hello", "World");
hasil:
"HelloWorld"
yaitu string.
Dan:
addition(10, "Hello");
hasil:
"10Hello"
yaitu string.
3. Masalahnya: TypeScript melihat return type terlalu umum
Dengan function tadi, TypeScript bisa menyimpulkan return type kurang lebih:
string | number
Jadi ketika kita menulis:
const result = addition("Hello", "World");
kita sebagai manusia tahu:
“Dua-duanya string, jadi hasilnya pasti string.”
Tetapi TypeScript bisa melihatnya sebagai:
string | number
Kemudian kita mencoba:
result.split(" ");
split() adalah method milik string.
Contoh:
const text = "Hello World";
text.split(" ");
Hasilnya:
["Hello", "World"]
Tetapi kalau TypeScript menganggap:
result: string | number
maka TypeScript akan berkata:
“Tunggu.
resultmungkinstring, tapi mungkin juganumber. Kalau ternyatanumber,split()tidak ada.”
Maka muncul error.
4. Kenapa TypeScript harus berhati-hati?
Bayangkan:
let result: string | number;
Kemudian:
result.split(" ");
TypeScript tidak boleh membiarkan ini begitu saja.
Karena mungkin:
result = "Hello World";
→ split() ada ✅
Tapi mungkin:
result = 123;
→ split() tidak ada ❌
Jadi TypeScript berpikir:
string | number
↓
Apakah pasti string?
↓
Tidak tahu
↓
Jangan izinkan split()
Ini justru merupakan salah satu manfaat TypeScript.
5. Di sinilah Function Overloading digunakan
Function Overloading memungkinkan kita memberitahu TypeScript:
“Kalau input-nya seperti ini, return type-nya seperti ini.”
Misalnya:
function addition(a: number, b: number): number;
function addition(a: string, b: string): string;
function addition(a: number, b: string): string;
function addition(a: string, b: number): string;
Sekarang kita memberikan beberapa signature untuk function addition.
6. Apa maksudnya signature?
Signature bisa kita anggap sebagai aturan penggunaan function.
Misalnya:
function addition(a: number, b: number): number;
Artinya:
Input:
number + number
Output:
number
Sedangkan:
function addition(a: string, b: string): string;
artinya:
Input:
string + string
Output:
string
Dan:
function addition(a: number, b: string): string;
artinya:
Input:
number + string
Output:
string
Jadi kita memberikan beberapa kemungkinan yang jelas kepada TypeScript.
7. Bentuk lengkap Function Overloading
Ada satu hal penting.
Function Overloading biasanya mempunyai dua bagian utama:
1. Overload signatures
Contohnya:
function addition(a: number, b: number): number;
function addition(a: string, b: string): string;
function addition(a: number, b: string): string;
function addition(a: string, b: number): string;
2. Implementation
Kemudian kita menulis implementation sebenarnya:
function addition(
a: string | number,
b: string | number
) {
if (typeof a === "string" || typeof b === "string") {
return a.toString() + b.toString();
}
return a + b;
}
Jadi bentuk lengkapnya:
function addition(a: number, b: number): number;
function addition(a: string, b: string): string;
function addition(a: number, b: string): string;
function addition(a: string, b: number): string;
function addition(
a: string | number,
b: string | number
) {
if (typeof a === "string" || typeof b === "string") {
return a.toString() + b.toString();
}
return a + b;
}
8. Kenapa nama function harus sama?
Perhatikan semua function di atas:
addition
addition
addition
addition
addition
Semuanya mempunyai nama yang sama.
Itulah yang membuatnya menjadi overload dari function yang sama.
Kita tidak membuat:
function additionNumber() {}
function additionString() {}
melainkan:
function addition(...) {}
function addition(...) {}
function addition(...) {}
dengan signature yang berbeda.
9. Sekarang lihat efeknya
Kita punya:
const result1 = addition(10, 20);
TypeScript melihat overload:
(number, number) → number
Maka:
result1
dianggap sebagai:
number
Jadi:
result1.toFixed(2);
boleh.
Tetapi:
result1.split(" ");
tidak boleh.
Karena number tidak memiliki split().
10. Bagaimana dengan string?
Sekarang:
const result2 = addition("Hello", "World");
TypeScript mencocokkan dengan:
(string, string) → string
Maka TypeScript tahu:
result2
adalah:
string
Jadi:
result2.split(" ");
boleh.
Inilah manfaat utama Function Overloading.
11. TypeScript seperti memilih aturan yang cocok
Bayangkan kita mempunyai daftar:
addition(number, number)
↓
number
addition(string, string)
↓
string
addition(number, string)
↓
string
addition(string, number)
↓
string
Kemudian kita memanggil:
addition(10, 20)
TypeScript mencari:
10 → number
20 → number
cocok dengan:
(number, number) → number
Maka hasil:
number
Kalau:
addition("10", 20)
TypeScript melihat:
"10" → string
20 → number
cocok dengan:
(string, number) → string
Maka hasil:
string
12. Jadi Overloading bukan berarti membuat banyak function runtime
Ini konsep yang sangat penting.
Kita mungkin melihat:
function addition(a: number, b: number): number;
function addition(a: string, b: string): string;
function addition(a: number, b: string): string;
Seolah-olah kita membuat tiga function.
Sebenarnya tidak.
Di TypeScript, signature-signature tersebut digunakan untuk membantu type checking.
Pada akhirnya implementation function-nya tetap satu:
function addition(
a: string | number,
b: string | number
) {
// implementation
}
Jadi secara konsep:
TypeScript
│
┌────────┼────────┐
↓ ↓ ↓
(number,number) (string,string)
↓ ↓
number string
│
↓
Implementation
│
↓
JavaScript
13. Hubungannya dengan Type Guard
Di dalam implementation kita masih menggunakan:
typeof
Contohnya:
if (typeof a === "string" || typeof b === "string") {
return a.toString() + b.toString();
}
Ini adalah Type Guard.
Jadi sebenarnya dua konsep bekerja bersama:
Function Overloading
Memberitahu TypeScript:
“Input tertentu menghasilkan output tertentu.”
Type Guard
Memberitahu TypeScript di dalam function:
“Sekarang kita sedang menangani tipe yang mana?”
14. Kenapa implementation masih menggunakan Union?
Perhatikan overload:
function addition(a: number, b: number): number;
function addition(a: string, b: string): string;
function addition(a: number, b: string): string;
function addition(a: string, b: number): string;
Tetapi implementation:
function addition(
a: string | number,
b: string | number
) {
...
}
Kenapa?
Karena implementation harus mampu menangani semua kemungkinan input yang kita izinkan.
Jadi:
Overload signatures
→ Memberi tahu caller apa saja yang boleh
→ Memberi tahu return type yang sesuai
Implementation
→ Menangani semua kemungkinan tersebut
15. Analogi restoran 🍽️
Bayangkan ada restoran bernama:
addition()
Restoran ini punya beberapa aturan menu:
Pesan:
10 + 20
→ mendapatkan makanan tipe NUMBER
Pesan:
"Hello" + "World"
→ mendapatkan makanan tipe STRING
Pesan:
10 + "Hello"
→ mendapatkan makanan tipe STRING
Menu yang tersedia adalah overload signatures.
Sedangkan dapurnya hanya satu:
DAPUR
↓
function implementation
Jadi:
Overload signature = daftar menu yang boleh dipesan. Implementation = dapur yang benar-benar mengerjakan pesanan.
16. Contoh lain yang lebih realistis
Function overloading tidak hanya untuk addition.
Misalnya kita mempunyai function:
function getValue(id: number): User;
function getValue(name: string): User;
Artinya:
getValue(10)
menghasilkan:
User
dan:
getValue("John")
juga menghasilkan:
User
Implementation-nya bisa:
function getValue(idOrName: number | string): User {
// mencari berdasarkan id atau name
}
17. Contoh dengan return type berbeda
Ini justru salah satu penggunaan menarik.
Misalnya:
function format(value: number): string;
function format(value: Date): string;
function format(value: string): string;
Artinya function bisa menerima tiga jenis input:
number → string
Date → string
string → string
Implementation:
function format(value: number | Date | string): string {
if (typeof value === "number") {
return value.toFixed(2);
}
if (typeof value === "string") {
return value.toUpperCase();
}
return value.toISOString();
}
18. Contoh yang lebih jelas: array
Misalnya kita membuat function getLength.
Kita ingin:
getLength("Hello")
menghasilkan:
number
dan:
getLength([1, 2, 3])
juga menghasilkan:
number
Kita bisa menulis:
function getLength(value: string): number;
function getLength(value: number[]): number;
function getLength(value: string | number[]): number {
return value.length;
}
Sekarang TypeScript tahu:
getLength("Hello")
→ number
dan:
getLength([1, 2, 3])
→ number.
19. Apa bedanya Overloading dengan Union Type?
Ini bagian yang sangat penting.
Tanpa overload:
function addition(
a: string | number,
b: string | number
): string | number {
// ...
}
TypeScript hanya tahu:
input:
string | number
output:
string | number
Hubungan antara input dan output kurang spesifik.
Dengan overload:
function addition(a: number, b: number): number;
function addition(a: string, b: string): string;
function addition(a: number, b: string): string;
function addition(a: string, b: number): string;
TypeScript tahu hubungan:
number + number
↓
number
dan:
string + string
↓
string
Jadi:
Union Type mengatakan “bisa A atau B”. Function Overloading bisa mengatakan “kalau input-nya A, output-nya X; kalau input-nya B, output-nya Y.”
20. Kenapa ini penting?
Misalnya:
const result = addition("Hello", "World");
Tanpa overload:
result: string | number
Akibatnya:
result.split(" ");
❌ Error.
Dengan overload:
result: string
Maka:
result.split(" ");
✅ Bisa.
Ini membuat autocomplete dan type checking TypeScript jauh lebih akurat.
21. Apa yang terjadi kalau input-nya tidak cocok?
Misalnya kita hanya punya:
function addition(a: number, b: number): number;
function addition(a: string, b: string): string;
Kemudian:
addition(true, false);
TypeScript akan error.
Karena tidak ada overload:
boolean + boolean
yang kita definisikan.
Begitu juga kalau:
addition(10, true);
Tidak ada signature yang cocok.
22. Satu hal yang sering membingungkan
Perhatikan ini:
function addition(a: number, b: number): number;
function addition(a: string, b: string): string;
function addition(
a: string | number,
b: string | number
) {
...
}
Kita tidak bisa memanggil function dengan semua kemungkinan yang disebut implementation.
Misalnya implementation menerima:
string | number
secara internal.
Tetapi caller hanya bisa menggunakan overload yang tersedia.
Jadi:
addition(10, 20); // ✅
addition("A", "B"); // ✅
addition(10, "B"); // ❌ jika overload ini tidak dibuat
Walaupun implementation secara teknis menerima number | string, yang menjadi “public API” bagi caller adalah overload signatures.
23. Pola yang perlu kamu hafalkan
Kalau melihat Function Overloading, biasanya bentuknya:
function namaFunction(parameter: TypeA): ReturnA;
function namaFunction(parameter: TypeB): ReturnB;
function namaFunction(parameter: TypeA | TypeB) {
// implementation
}
Dengan beberapa parameter:
function namaFunction(a: TypeA, b: TypeB): ReturnType;
function namaFunction(a: TypeC, b: TypeD): AnotherReturnType;
function namaFunction(
a: TypeA | TypeC,
b: TypeB | TypeD
) {
// implementation
}
24. Kapan kita menggunakan Function Overloading?
Gunakan ketika:
1. Satu function memang mempunyai beberapa cara penggunaan
Misalnya:
getUser(10)
atau:
getUser("john")
2. Return type bergantung pada tipe input
Misalnya:
input tertentu → string
input lain → number
3. Kita ingin autocomplete TypeScript lebih akurat
Daripada:
string | number
kita bisa memberikan informasi yang lebih spesifik.
4. API function mempunyai beberapa bentuk input yang jelas
Contohnya function library atau utility yang mendukung beberapa jenis parameter.
25. Jangan gunakan overload kalau sebenarnya tidak perlu
Misalnya:
function print(value: string | number): void {
console.log(value);
}
Kalau return type-nya selalu void, overload mungkin tidak memberikan manfaat besar.
Tidak perlu membuat:
function print(value: string): void;
function print(value: number): void;
kalau sebenarnya tidak ada perbedaan perilaku/return type yang penting.
Jadi Function Overloading paling berguna ketika perbedaan input memang mempunyai hubungan dengan output atau perilaku function.
26. Kesalahan umum saat memahami Overloading
❌ Salah paham #1
“Function overloading berarti ada banyak function dengan nama sama yang berjalan bersamaan.”
Bukan.
Di TypeScript, overload signatures terutama digunakan untuk type checking. Implementation runtime-nya tetap satu.
❌ Salah paham #2
“Overload mengubah function menjadi beberapa function.”
Tidak.
Tidak ada transformasi runtime seperti itu.
❌ Salah paham #3
“Union dan overload sama saja.”
Tidak.
Union:
string | number
hanya mengatakan:
Bisa string atau number.
Overload:
function fn(value: string): string;
function fn(value: number): number;
mengatakan:
Kalau input string → output string. Kalau input number → output number.
Hubungan input-output menjadi lebih jelas.
27. Gambaran besarnya
Coba lihat alurnya:
FUNCTION OVERLOADING
│
▼
Kita punya beberapa
cara memanggil function
│
┌──────────┼──────────┐
▼ ▼ ▼
input A input B input C
│ │ │
▼ ▼ ▼
output A output B output C
│
▼
IMPLEMENTATION
│
▼
Menangani semua kasus
28. Hubungkan dengan materi Type Guard sebelumnya
Ini sebenarnya nyambung sekali dengan materi sebelumnya.
Kita punya:
function addition(
a: string | number,
b: string | number
) {
if (typeof a === "string" || typeof b === "string") {
return a.toString() + b.toString();
}
return a + b;
}
Di sini:
string | number
→ Union Type
Kemudian:
typeof a === "string"
→ Type Guard
Kemudian kita tambahkan:
function addition(a: string, b: string): string;
function addition(a: number, b: number): number;
→ Function Overloading
Jadi ketiga konsep ini bisa bekerja bersama:
Union Type
↓
"Input bisa beberapa tipe"
Type Guard
↓
"Cek tipe sebenarnya"
Function Overloading
↓
"Jelaskan hubungan input dengan output
kepada TypeScript"
29. Ringkasan Function Overloading
Kalau kamu ditanya:
“Apa itu Function Overloading?”
Jawaban sederhananya:
Function Overloading adalah teknik TypeScript untuk mendefinisikan beberapa signature untuk satu function, sehingga TypeScript dapat mengetahui tipe return yang tepat berdasarkan tipe parameter yang diberikan.
Contoh:
function addition(a: number, b: number): number;
function addition(a: string, b: string): string;
function addition(
a: string | number,
b: string | number
) {
if (typeof a === "string" || typeof b === "string") {
return a.toString() + b.toString();
}
return a + b;
}
Kemudian:
const a = addition(10, 20);
// number
const b = addition("Hello", "World");
// string
Jadi TypeScript bisa memahami konteksnya.
🧠 Cheat Sheet
UNION TYPE
string | number
↓
"bisa string ATAU number"
TYPE GUARD
typeof value === "string"
↓
"cek tipe value saat runtime"
FUNCTION OVERLOADING
function fn(string): string;
function fn(number): number;
↓
"kalau input string → output string
kalau input number → output number"
Pola utama:
// 1. Overload signatures
function fn(value: string): string;
function fn(value: number): number;
// 2. Implementation
function fn(value: string | number) {
// logic
}
Kalimat paling gampang untuk diingat:
🔑 Union memberi tahu “input bisa beberapa tipe”, sedangkan Function Overloading memberi tahu “untuk input tertentu, return type-nya apa”.
Dan dalam contoh lecture:
addition(10, 20)
↓
number + number
↓
number
addition("10", "20")
↓
string + string
↓
string
Itulah alasan split() yang sebelumnya error bisa menjadi valid setelah kita menggunakan Function Overloading: TypeScript sekarang tidak lagi hanya melihat string | number, tetapi bisa menentukan bahwa addition("...", "...") secara spesifik menghasilkan string.