Mengenal TypeScript: Optional Properties, Optional Chaining, & Enum

This article has been translated into English version: Learn TypeScript: Optional Properties, Optional Chaining, & Enum
TypeScript menawarkan sistem tipe data yang kuat untuk membantu pengembangan aplikasi yang lebih aman dan mudah dipelihara. Artikel ini akan membahas dua fitur penting dalam sistem tipe TypeScript: Optional Properties, Optional Chaining, dan Enum.
Optional Properties
Dalam TypeScript, kita bisa menandai properti sebagai opsional dengan menambahkan tanda tanya (?
) setelah nama properti. Ini berarti properti tersebut boleh ada atau tidak ada dalam sebuah objek.
/** Mendefinisikan tipe dengan optional properties */
type User = {
id: number;
name: string;
/** email adalah optional property */
email?: string;
/** phone adalah optional property */
phone?: string;
};
/** Membuat objek tanpa mengisi properti opsional */
const user1: User = {
id: 1,
name: "Budi",
};
/** Membuat objek dengan mengisi properti opsional */
const user2: User = {
id: 2,
name: "Ani",
email: "ani@example.com",
phone: "08123456789",
};
Manfaat Optional Properties
Beberapa manfaat dari optional properties antara lain:
Fleksibilitas
Memungkinkan kita membuat struktur data yang fleksibel tanpa kehilangan keamanan tipe.
Validasi
TypeScript akan memvalidasi bahwa properti wajib selalu ada.
Dokumentasi
Kode menjadi lebih ekspresif dan self-documenting.
Optional Chaining
Optional chaining adalah fitur yang memungkinkan kita mengakses properti atau memanggil metode dari objek yang mungkin null
atau undefined
tanpa menyebabkan error. Fitur ini direpresentasikan dengan operator ?.
.
type Address = {
street: string;
city: string;
postalCode?: string;
};
type User = {
id: number;
name: string;
address?: Address;
};
function getPostalCode(user: User): string | undefined {
// Tanpa optional chaining
// if (user.address && user.address.postalCode) {
// return user.address.postalCode;
// }
// return undefined;
// Dengan optional chaining
return user.address?.postalCode;
}
const user1: User = {
id: 1,
name: "Dian",
};
const user2: User = {
id: 2,
name: "Eko",
address: {
street: "Jl. Merdeka",
city: "Jakarta",
},
};
const user3: User = {
id: 3,
name: "Fira",
address: {
street: "Jl. Sudirman",
city: "Jakarta",
postalCode: "12345",
},
};
console.log(getPostalCode(user1)); // undefined
console.log(getPostalCode(user2)); // undefined
console.log(getPostalCode(user3)); // "12345"
Optional Chaining dengan Method
Optional chaining juga bisa digunakan untuk memanggil method yang mungkin tidak ada.
type Calculator = {
add: (a: number, b: number) => number;
subtract?: (a: number, b: number) => number;
};
const basicCalc: Calculator = {
add: (a, b) => a + b,
};
const fullCalc: Calculator = {
add: (a, b) => a + b,
subtract: (a, b) => a - b,
};
// Memanggil method yang mungkin tidak ada
console.log(basicCalc.subtract?.(5, 3)); // undefined
console.log(fullCalc.subtract?.(5, 3)); // 2
Nullish Coalescing Operator
Optional chaining sering digunakan bersama dengan nullish coalescing operator (??
) untuk memberikan nilai default ketika hasilnya null
atau undefined
.
function getCity(user: User): string {
return user.address?.city ?? "Kota tidak diketahui";
}
console.log(getCity(user1)); // "Kota tidak diketahui"
console.log(getCity(user2)); // "Jakarta"
Enum
Enum (enumeration) adalah cara untuk mendefinisikan sekelompok konstanta bernama. Enum memudahkan kita untuk mendokumentasikan maksud atau membuat kumpulan kasus yang berbeda.
/** Mendefinisikan enum */
enum Direction {
Up,
Down,
Left,
Right,
}
/** Menggunakan enum */
function move(direction: Direction): void {
switch (direction) {
case Direction.Up:
console.log("Bergerak ke atas");
break;
case Direction.Down:
console.log("Bergerak ke bawah");
break;
case Direction.Left:
console.log("Bergerak ke kiri");
break;
case Direction.Right:
console.log("Bergerak ke kanan");
break;
}
}
move(Direction.Up); // "Bergerak ke atas"
move(Direction.Right); // "Bergerak ke kanan"
Enum dengan Nilai Eksplisit
Secara default, enum akan memberikan nilai numerik dimulai dari 0. Kita juga bisa memberikan nilai eksplisit untuk setiap anggota enum.
/** Enum dengan nilai string */
enum ApiStatus {
Success = "SUCCESS",
Error = "ERROR",
Loading = "LOADING",
}
function handleApiResponse(status: ApiStatus): void {
if (status === ApiStatus.Success) {
console.log("API berhasil");
} else if (status === ApiStatus.Error) {
console.log("API gagal");
} else {
console.log("API sedang loading");
}
}
handleApiResponse(ApiStatus.Success); // "API berhasil"
Const Enum
Untuk optimasi performa, TypeScript menyediakan const enum
yang akan dihapus sepenuhnya saat kompilasi dan digantikan dengan nilai literalnya.
/** Const enum */
const enum HttpStatus {
OK = 200,
Created = 201,
BadRequest = 400,
Unauthorized = 401,
NotFound = 404,
InternalServerError = 500,
}
function handleHttpResponse(status: number): void {
if (status === HttpStatus.OK) {
console.log("Request berhasil");
} else if (status === HttpStatus.NotFound) {
console.log("Resource tidak ditemukan");
} else if (status >= HttpStatus.BadRequest) {
console.log("Terjadi error");
}
}
handleHttpResponse(HttpStatus.OK); // "Request berhasil"
handleHttpResponse(HttpStatus.NotFound); // "Resource tidak ditemukan"
Enum vs Union Type
Dalam beberapa kasus, union type dari literal values bisa menjadi alternatif yang lebih baik daripada enum, terutama jika kita ingin pendekatan yang lebih functional.
/** Menggunakan enum */
enum Theme {
Light,
Dark,
System,
}
/** Menggunakan union type */
type ThemeType = "light" | "dark" | "system";
/** Fungsi dengan enum */
function setThemeEnum(theme: Theme): void {
// implementasi
}
/** Fungsi dengan union type */
function setThemeUnion(theme: ThemeType): void {
// implementasi
}
// Penggunaan
setThemeEnum(Theme.Dark);
setThemeUnion("dark");
Union type memberikan type-safety yang sama dengan enum, tetapi dengan sintaks yang lebih sederhana dan tanpa perlu mendefinisikan tipe tambahan.
Kesimpulan
Optional properties dan optional chaining memberikan fleksibilitas dalam menangani data yang mungkin tidak lengkap, sementara enum menyediakan cara untuk mendefinisikan sekelompok konstanta terkait. Kedua fitur ini merupakan bagian penting dari sistem tipe TypeScript yang membantu kita menulis kode yang lebih aman, ekspresif, dan mudah dipelihara.
Dengan memahami dan memanfaatkan fitur-fitur ini, kita dapat mengembangkan aplikasi TypeScript yang lebih robust dan menghindari banyak bug yang biasanya muncul dalam pengembangan JavaScript biasa.