Masukkan Password
11 Tipe Union di TypeScript
1. Apa itu Union Type?
Kata union secara sederhana bisa dipahami sebagai gabungan beberapa kemungkinan tipe.
Syntax-nya menggunakan simbol:
|
yang disebut pipe.
Contoh:
let value: string | number;
Bacanya:
valuebisa berupastringataunumber.
Jadi:
value = "Hello"; // ✅
value = 100; // ✅
Tetapi:
value = true; // ❌
value = []; // ❌
Kenapa?
Karena kita hanya mengizinkan:
string
ATAU
number
bukan boolean atau array.
2. Kenapa kita membutuhkan Union Type?
Sebelum memahami syntax-nya, kita perlu memahami masalah yang ingin diselesaikan.
Bayangkan kita memiliki function:
function printStatus(message: string, code: ???) {
...
}
message jelas berupa string.
Tetapi bagaimana dengan code?
Dalam sebuah aplikasi, status code bisa saja dikirim sebagai:
200
atau:
"200"
Misalnya:
printStatus("Request successful", 200);
dan:
printStatus("Request successful", "200");
Kita ingin keduanya valid.
Tetapi kita tidak ingin menerima sembarang tipe:
printStatus("Request successful", true);
atau:
printStatus("Request successful", []);
Nah, Union Type cocok untuk kasus seperti ini.
function printStatus(message: string, code: string | number) {
console.log(`${message}, status code ${code}`);
}
Sekarang:
printStatus("Request was successful", 200);
// ✅
printStatus("Resource was not found", "404");
// ✅
Tetapi:
printStatus("Something happened", true);
// ❌
Karena boolean tidak termasuk dalam union:
string | number
3. Union Type pada Variable
Di lecture, contoh pertama adalah sebuah variable yang bisa menyimpan object atau null.
Misalnya kita punya user.
User normal bentuknya:
{
name: "John",
age: 28
}
Tetapi pada kondisi tertentu, user mungkin belum ditemukan sehingga nilainya:
null
Jadi variable kita memiliki dua kemungkinan:
User Object
ATAU
null
Kita bisa menuliskannya:
let user: {
name: string;
age: number;
} | null = null;
Perhatikan bagian ini:
{
name: string;
age: number;
} | null
Artinya:
userboleh berupa object dengannamestring danagenumber, ATAUnull.
4. Kenapa menggunakan let, bukan const?
Ini bagian penting dari contoh lecture.
Awalnya:
const user = null;
Kemudian kita ingin mengubahnya:
user = {
name: "John",
age: 28
};
Ini akan error.
Karena const tidak boleh di-reassign.
Jadi kita menggunakan:
let user: {
name: string;
age: number;
} | null = null;
Sekarang:
user = {
name: "John",
age: 28
};
valid.
Dan variable tersebut juga boleh kembali menjadi:
user = null;
Karena null memang termasuk dalam Union Type-nya.
5. Contoh Lengkap getUser
Mari kita sederhanakan contoh dari lecture.
let username = "John";
let userAge = 28;
function getUser() {
let user: {
name: string;
age: number;
} | null = null;
user = {
name: username,
age: userAge
};
return user;
}
Perhatikan variable:
let user: {
name: string;
age: number;
} | null = null;
Pada awalnya:
user
↓
null
Kemudian:
user = {
name: username,
age: userAge
};
menjadi:
user
↓
{
name: "John",
age: 28
}
Jadi selama program berjalan, user memiliki dua kemungkinan keadaan:
┌───────────────┐
│ user │
└───────┬───────┘
│
├── object
│ { name, age }
│
└── null
Itulah Union Type.
6. Union Type pada Return Type Function
Union Type tidak hanya bisa digunakan pada variable.
Kita juga bisa menggunakannya pada return type function.
Misalnya:
function getUser(): {
name: string;
age: number;
} | null {
// ...
}
Artinya function tersebut bisa mengembalikan:
{
name: "John",
age: 28
}
atau:
null
Jadi:
Return value
│
├── User Object
│
└── null
Ini sangat berguna untuk function yang mungkin berhasil mendapatkan data atau tidak mendapatkan data.
7. Union Type pada Parameter Function
Sekarang masuk ke contoh kedua dari lecture.
Kita punya:
function printStatus(message: string, code: string | number) {
console.log(`${message}, status code ${code}`);
}
Ada dua parameter:
message: string
dan:
code: string | number
Parameter message hanya boleh:
string
Sedangkan code boleh:
string
atau:
number
Contoh:
printStatus("Request was successful", 200);
Valid.
printStatus("Resource was not found", "404");
Juga valid.
Tetapi:
printStatus("Error", true);
Error.
8. Kenapa string | number lebih baik daripada any?
Ini penting karena sebelumnya kita sudah belajar tentang any.
Kita sebenarnya bisa saja menulis:
function printStatus(message: string, code: any) {
...
}
Tapi masalahnya adalah any terlalu bebas.
Dengan any:
code = "200"; // ✅
code = 200; // ✅
code = true; // ✅
code = []; // ✅
code = {}; // ✅
Padahal kita sebenarnya hanya menginginkan:
string ATAU number
Maka lebih baik:
code: string | number
Sekarang TypeScript membantu kita membatasi kemungkinan.
code = "200"; // ✅
code = 200; // ✅
code = true; // ❌
code = []; // ❌
Jadi:
Union Type adalah alternatif yang jauh lebih aman daripada menggunakan
anyketika kita tahu kemungkinan tipe yang diperbolehkan.
9. Bagian paling penting: Masalah dengan Union Type
Ini adalah bagian paling penting dari lecture.
Misalnya kita memiliki:
function printStatus(message: string, code: string | number) {
console.log(code.trim());
}
Kita mungkin berpikir:
“Kan
codebisa string, jadi saya bisa menggunakan.trim().”
Ternyata TypeScript akan memberikan error.
Kenapa?
Karena:
string | number
berarti code belum tentu string.
Bisa saja:
code = " 404 ";
atau:
code = 404;
Method:
.trim()
tersedia pada string.
Contoh:
" 404 ".trim();
Tetapi tidak tersedia pada number.
404.trim(); // ❌
Jadi TypeScript berpikir:
“Bagaimana kalau
codeternyata number? Kalau saya izinkan.trim(), program bisa gagal.”
Karena itu TypeScript mencegah kita.
10. Aturan penting Union Type
Dari sini ada sebuah aturan yang sangat penting:
Sebelum menggunakan property atau method pada value yang memiliki Union Type, property/method tersebut harus aman untuk semua kemungkinan tipe dalam union tersebut.
Misalnya:
let value: string | number;
Kita tidak boleh sembarangan melakukan:
value.trim();
Karena:
string → punya trim()
number → tidak punya trim()
Jadi tidak aman.
11. Bagaimana cara mengatasinya?
Kita harus memberitahu TypeScript:
“Kalau
codeadalah string, lakukan.trim().”
Caranya dengan pengecekan.
if (typeof code === "string") {
code = code.trim();
}
Sekarang TypeScript bisa memahami kondisinya.
Kita bisa menulis:
function printStatus(message: string, code: string | number) {
if (typeof code === "string") {
code = code.trim();
}
console.log(`${message}, status code ${code}`);
}
Kalau:
printStatus("Resource was not found", " 404 ");
maka:
" 404 "
akan menjadi:
"404"
Sedangkan kalau:
printStatus("Request was successful", 200);
TypeScript tahu bahwa:
typeof code === "string"
adalah false.
Jadi .trim() tidak dijalankan.
12. Ini disebut Type Narrowing
Teknik seperti ini:
if (typeof code === "string") {
code.trim();
}
sebenarnya merupakan konsep yang sangat penting di TypeScript yang disebut type narrowing.
Awalnya TypeScript melihat:
code: string | number
Kemungkinannya ada dua:
string
number
Setelah kita melakukan:
if (typeof code === "string")
di dalam blok tersebut TypeScript tahu:
code = string
Sehingga:
code.trim();
menjadi aman.
Secara sederhana:
Sebelum pengecekan
↓
string | number
↓
typeof === "string"
↓
Di dalam if
↓
string
Ini adalah salah satu kemampuan TypeScript yang sangat berguna.
13. Kenapa TypeScript tidak langsung tahu?
Mungkin muncul pertanyaan:
“Kan kita yang membuat function-nya. Kenapa TypeScript tidak tahu
codeitu string atau number?”
Karena function ini:
function printStatus(message: string, code: string | number) {
}
bisa dipanggil dari banyak tempat.
Misalnya:
printStatus("Success", 200);
atau:
printStatus("Not found", "404");
Ketika function sedang dijalankan, TypeScript perlu menganggap bahwa kedua kemungkinan tersebut valid.
Karena itu kita harus menangani kedua kemungkinan tersebut dengan aman.
14. Contoh lain supaya lebih mudah
Misalnya:
let data: string | number;
Kita tidak tahu saat ini data isinya apa.
Bisa:
data = "Hello";
atau:
data = 100;
Kalau kita ingin menggunakan method string:
data.toUpperCase();
TypeScript akan menolak.
Karena:
string → punya toUpperCase()
number → tidak punya toUpperCase()
Maka:
if (typeof data === "string") {
console.log(data.toUpperCase());
}
Sekarang aman.
15. Tapi ada operasi yang bisa digunakan langsung
Kalau sebuah property atau method tersedia pada semua tipe dalam Union Type, maka kita bisa menggunakannya.
Contohnya:
let value: string | number;
Kita tahu bahwa keduanya bisa digunakan dalam konteks tertentu seperti operasi yang kompatibel dengan keduanya, tetapi untuk method/property spesifik kita harus hati-hati.
Prinsip sederhananya:
Kalau belum melakukan narrowing, gunakan hanya sesuatu yang TypeScript yakin tersedia pada semua kemungkinan tipe.
16. Union Type bisa lebih dari dua tipe
Di lecture, awalnya kita menggunakan:
string | number
Tetapi Union Type tidak terbatas hanya dua tipe.
Misalnya:
let value: string | number | boolean;
Sekarang value bisa berupa:
"Hello" // ✅
100 // ✅
true // ✅
Tetapi:
[] // ❌
karena array tidak termasuk.
17. Bahkan bisa menambahkan null
null juga bisa menjadi bagian dari Union Type.
Contoh:
let value: string | number | boolean | null;
Berarti ada empat kemungkinan:
string
OR
number
OR
boolean
OR
null
Contoh:
value = "Hello"; // ✅
value = 100; // ✅
value = true; // ✅
value = null; // ✅
18. Union Type dengan Literal Type
Nanti ketika konsep TypeScript kita semakin maju, Union Type bisa digabungkan dengan literal type.
Misalnya:
let role: "admin" | "user" | "guest";
Sekarang role hanya boleh memiliki salah satu dari tiga value:
role = "admin"; // ✅
role = "user"; // ✅
role = "guest"; // ✅
Tetapi:
role = "manager"; // ❌
Ini sangat berguna untuk membuat pilihan yang terbatas.
19. Bedakan Union Type dengan Array
Ini juga penting.
Union Type
let value: string | number;
Artinya satu value bisa berupa string atau number.
Misalnya:
value = "Hello";
Kemudian:
value = 100;
Array
let values: (string | number)[];
Artinya array tersebut bisa memiliki banyak element, dan setiap element boleh berupa string atau number.
Contoh:
let values: (string | number)[] = [
"John",
20,
"London",
100
];
Jadi perhatikan perbedaannya:
string | number
→ satu value, salah satu dari dua tipe.
Sedangkan:
(string | number)[]
→ array yang element-elementnya boleh string atau number.
20. Union Type vs any
Ini sangat penting untuk menghubungkan dengan lecture sebelumnya.
any
let data: any;
TypeScript pada dasarnya membiarkan hampir apa saja:
data = "Hello";
data = 100;
data = true;
data = [];
data = {};
Union
let data: string | number;
Hanya:
data = "Hello"; // ✅
data = 100; // ✅
Tetapi:
data = true; // ❌
data = []; // ❌
Jadi:
any
│
├── string
├── number
├── boolean
├── array
├── object
└── dll
Sedangkan:
string | number
│
├── string
└── number
Union Type lebih spesifik dan lebih aman.
21. Union Type vs Object
Kita juga bisa menggabungkan konsep yang sudah kita pelajari sebelumnya.
Misalnya kita punya:
let user: {
name: string;
age: number;
} | null;
Di sini sebenarnya kita menggabungkan dua konsep:
Object type
{
name: string;
age: number;
}
dengan:
Union Type
| null
Sehingga hasil akhirnya:
{
name: string;
age: number;
} | null
Bacanya:
userbisa berupa object yang mempunyainamestring danagenumber, ataunull.
22. Cara berpikir yang paling mudah
Kalau kamu melihat:
string | number
langsung baca:
“string ATAU number.”
Kalau melihat:
string | number | boolean
baca:
“string ATAU number ATAU boolean.”
Kalau melihat:
User | null
baca:
“User ATAU tidak ada value (
null).”
Kalau melihat:
string | null
baca:
“string ATAU null.”
Kata “ATAU” adalah kunci utama untuk memahami Union Type.
23. Contoh kasus nyata
Union Type sangat sering digunakan ketika kita berurusan dengan data yang bisa memiliki beberapa kondisi.
Misalnya status pembayaran:
let paymentStatus: "pending" | "success" | "failed";
Artinya:
pending
ATAU
success
ATAU
failed
Atau API response:
let response: User | null;
Artinya:
User ditemukan
ATAU
User tidak ditemukan
Atau ID:
let userId: number | string;
Artinya ID bisa datang sebagai:
123
atau:
"123"
24. Hubungan dengan Type Annotation
Dari lecture sebelumnya kita sudah belajar:
let age: number = 20;
Ini adalah type annotation.
Sekarang Union Type sebenarnya adalah type annotation yang memiliki beberapa kemungkinan.
let age: number = 20;
→ hanya number.
Sedangkan:
let value: number | string = 20;
→ number atau string.
Jadi Union Type bukan konsep yang terpisah jauh dari yang sudah kita pelajari.
Ini adalah pengembangan dari konsep type annotation.
25. Hubungan dengan Type Inference
Misalnya:
let age = 20;
TypeScript melakukan inference:
age → number
Tetapi kalau kita memang ingin memberikan beberapa kemungkinan tipe:
let value: string | number = 20;
kita memberikan annotation secara eksplisit.
26. Kesalahan yang harus dihindari
Kesalahan umum adalah menganggap:
string | number
berarti:
“Value ini bisa string dan number sekaligus.”
Bukan begitu.
Yang benar:
Value tersebut bisa berupa string ATAU number.
Pada satu waktu, value-nya tetap merupakan satu nilai.
Misalnya:
let value: string | number = "Hello";
Saat ini value-nya adalah string.
Kemudian:
value = 100;
Sekarang value-nya number.
27. Kesalahan kedua: menganggap Union = any
Jangan berpikir:
string | number
sama dengan:
any
Tidak sama.
any
sangat luas.
Sedangkan:
string | number
sangat spesifik.
Kalau kita tahu kemungkinan tipe yang diperbolehkan, lebih baik menggunakan Union Type daripada any.
28. Cheat Sheet
| Syntax | Artinya |
|---|---|
string | hanya string |
number | hanya number |
string | number | string ATAU number |
string | number | boolean | string ATAU number ATAU boolean |
string | null | string ATAU null |
User | null | User ATAU null |
any | hampir bebas tipe |
(string | number)[] | array berisi string/number |
29. Inti lecture ini
Kalau saya ringkas menjadi beberapa poin:
1. Union Type menggunakan |
let value: string | number;
2. Artinya value memiliki beberapa kemungkinan tipe
string ATAU number
3. Bisa digunakan pada variable
let user: User | null;
4. Bisa digunakan pada parameter
function printStatus(code: string | number) {}
5. Bisa digunakan pada return type
function getUser(): User | null {
// ...
}
6. Bisa memiliki lebih dari dua tipe
string | number | boolean | null
7. Harus hati-hati dengan method/property
Jika:
value: string | number
maka:
value.trim();
tidak aman karena trim() hanya tersedia untuk string.
8. Gunakan type narrowing
if (typeof value === "string") {
value.trim();
}
Sekarang TypeScript tahu bahwa di dalam if, value adalah string.
🧠 Cara paling gampang mengingatnya
Bayangkan Union Type seperti pintu dengan beberapa jalur yang diizinkan.
value
│
┌──────┴──────┐
↓ ↓
string number
"Hello" 100
TypeScript mengatakan:
“Saya mengizinkan kamu masuk lewat jalur string ATAU jalur number. Tapi kalau kamu datang sebagai boolean, kamu tidak boleh masuk.”
Dan ketika kita belum tahu jalur mana yang sedang digunakan, kita harus melakukan pengecekan terlebih dahulu sebelum memakai sesuatu yang hanya tersedia di salah satu jalur.
Jadi satu kalimat yang wajib kamu ingat dari lecture ini adalah:
Union Type (
|) digunakan ketika satu value boleh memiliki salah satu dari beberapa tipe yang telah kita tentukan, dan sebelum menggunakan fitur khusus suatu tipe, kita perlu memastikan value tersebut memang tipe yang sesuai.
Kalau kamu mau, saya juga bisa membuat gambar visual yang menjelaskan alur Union Type + Type Narrowing supaya konsep string | number ini lebih gampang diingat.