Panduan Pemula untuk Tipe Mapped dalam TypeScript

Hai sana, para ahli TypeScript masa depan! Hari ini, kita akan memulai perjalanan yang menarik ke dalam dunia Tipe Mapped. Jangan khawatir jika Anda baru dalam pemrograman - saya akan menjadi panduan ramah Anda, dan kita akan berjalan langkah demi langkah. Pada akhir panduan ini, Anda akan dapat memetakan tipe seperti seorang pro!

TypeScript - Mapped Types

Apa Itu Tipe Mapped?

Sebelum kita mendalam, mari kita memahami apa itu Tipe Mapped. Bayangkan Anda memiliki kotak cokelat campuran, dan Anda ingin membuat kotak baru di mana setiap cokelat diwrapping dengan foil emas. Itu adalah esensi apa yang dilakukan Tipe Mapped dalam TypeScript - mereka mengambil tipe yang sudah ada dan transformasikan menjadi tipe baru berdasarkan set aturan.

Tipe Mapped Bawaan

TypeScript datang dengan beberapa Tipe Mapped yang sudah didefinisikan dan sangat berguna. Mari kita lihat satu per satu:

1. Partial<T>

Tipe Partial<T> membuat semua properti T menjadi opsional. Itu seperti mengubah resep ketat menjadi resep fleksibel di mana Anda dapat melewatkan beberapa bahan.

interface Recipe {
name: string;
ingredients: string[];
cookingTime: number;
}

type FlexibleRecipe = Partial<Recipe>;

// Sekarang kita dapat membuat resep tanpa semua properti
const quickSnack: FlexibleRecipe = {
name: "Toast",
// Kita dapat melewatkan ingredients dan cookingTime
};

Dalam contoh ini, FlexibleRecipe memungkinkan kita membuat resep tanpa menentukan semua properti. Itu sempurna saat Anda ingin memperbarui hanya sebagian objek.

2. Required<T>

Required<T> adalah kebalikan dari Partial<T>. Itu membuat semua properti wajib, bahkan jika mereka opsional dalam tipe asli.

interface UserProfile {
name: string;
age?: number;
email?: string;
}

type CompleteUserProfile = Required<UserProfile>;

// Sekarang kita harus menyediakan semua properti
const user: CompleteUserProfile = {
name: "Alice",
age: 30,
email: "[email protected]"
};

Di sini, CompleteUserProfile memastikan bahwa kita menyediakan semua properti, termasuk age dan email yang opsional dalam UserProfile.

3. Readonly<T>

Readonly<T> membuat semua properti T menjadi read-only. Itu seperti memasukkan tipe Anda ke dalam kaca - Anda dapat melihat, tetapi Anda tidak dapat menyentuh!

interface Toy {
name: string;
price: number;
}

type CollectibleToy = Readonly<Toy>;

const actionFigure: CollectibleToy = {
name: "Superhero",
price: 19.99
};

// Ini akan menyebabkan kesalahan
// actionFigure.price = 29.99;

Dalam contoh ini, setelah kita membuat actionFigure, kita tidak dapat mengubah propertinya. Itu bagus untuk membuat objek tak dapat diubah.

4. Pick<T, K>

Pick<T, K> membuat tipe baru dengan memilih hanya properti yang ditentukan K dari T. Itu seperti memilih fitur favorit Anda dari tipe.

interface Smartphone {
brand: string;
model: string;
year: number;
color: string;
price: number;
}

type BasicPhoneInfo = Pick<Smartphone, 'brand' | 'model'>;

const myPhone: BasicPhoneInfo = {
brand: "TechBrand",
model: "X2000"
};

Di sini, BasicPhoneInfo hanya termasuk brand dan model properti dari Smartphone, meninggalkan yang lain.

5. Omit<T, K>

Omit<T, K> adalah kebalikan dari Pick<T, K>. Itu membuat tipe baru tanpa properti yang ditentukan K dari T.

interface Book {
title: string;
author: string;
pages: number;
isbn: string;
}

type BookPreview = Omit<Book, 'pages' | 'isbn'>;

const preview: BookPreview = {
title: "TypeScript Adventures",
author: "Code Wizard"
};

Dalam kasus ini, BookPreview termasuk semua properti Book kecuali pages dan isbn.

Contoh Penggunaan Tipe Mapped

Sekarang kita telah melihat Tipe Mapped bawaan, mari kita lihat beberapa contoh praktis bagaimana kita dapat menggunakannya dalam konteks dunia nyata.

Contoh 1: Membuat State Form

Bayangkan Anda sedang membuat form, dan Anda ingin mencatat field mana yang telah diubah:

interface LoginForm {
username: string;
password: string;
rememberMe: boolean;
}

type FormTouched = { [K in keyof LoginForm]: boolean };

const touchedFields: FormTouched = {
username: true,
password: false,
rememberMe: true
};

Di sini, kita telah membuat FormTouched tipe yang memiliki semua kunci seperti LoginForm, tetapi semua nilai adalah boolean yang menunjukkan apakah field tersebut telah ditentukan.

Contoh 2: Wrapper Respon API

Bayangkan Anda memiliki API yang mengembalikan jenis data yang berbeda, dan Anda ingin membungkus setiap respon dalam format standar:

interface ApiResponse<T> {
data: T;
status: 'success' | 'error';
timestamp: number;
}

type UserData = { id: number; name: string; email: string };
type ProductData = { id: number; name: string; price: number };

const userResponse: ApiResponse<UserData> = {
data: { id: 1, name: "John Doe", email: "[email protected]" },
status: 'success',
timestamp: Date.now()
};

const productResponse: ApiResponse<ProductData> = {
data: { id: 101, name: "Laptop", price: 999.99 },
status: 'success',
timestamp: Date.now()
};

Contoh ini menunjukkan bagaimana kita dapat menggunakan jenis generik dengan Tipe Mapped untuk membuat struktur jenis yang fleksibel dan dapat digunakan kembali.

Membuat Tipe Mapped Khusus

Sekarang, mari kita fungsikan otak TypeScript kita dan buat beberapa Tipe Mapped khusus!

Tipe Khusus 1: Nullable

Buatlah jenis yang membuat semua properti nullable:

type Nullable<T> = { [K in keyof T]: T[K] | null };

interface Person {
name: string;
age: number;
}

type NullablePerson = Nullable<Person>;

const maybePerson: NullablePerson = {
name: "Jane",
age: null  // Ini sekarang valid
};

Jenis Nullable<T> memungkinkan setiap properti untuk menjadi jenis aslinya atau null.

Tipe Khusus 2: Freezable

Buatlah jenis yang menambahkan metode freeze ke objek:

type Freezable<T> = T & { freeze(): Readonly<T> };

interface Config {
theme: string;
fontSize: number;
}

function makeFreezable<T>(obj: T): Freezable<T> {
return {
...obj,
freeze() {
return Object.freeze({ ...this }) as Readonly<T>;
}
};
}

const config = makeFreezable<Config>({
theme: "dark",
fontSize: 14
});

const frozenConfig = config.freeze();
// frozenConfig.theme = "light";  // Ini akan menyebabkan kesalahan

Jenis ini menambahkan metode freeze ke setiap objek, memungkinkan kita untuk membuat versi tak dapat diubah dari itu.

Kesimpulan

Wah, kita telah menempuh jarak yang cukup hari ini! Dari Tipe Mapped bawaan ke membuat jenis khusus sendiri, Anda telah melihat betapa kuat dan fleksibel TypeScript dapat menjadi. Tipe Mapped adalah seperti tongkat sihir dalam peralatan TypeScript Anda - mereka memungkinkan Anda untuk transformasi dan manipulasi jenis dalam cara yang sangat berguna.

Ingat, kunci untuk menguasai Tipe Mapped adalah latihan. Cobalah membuat jenis Anda sendiri, eksperimen dengan kombinasi yang berbeda, dan segera Anda akan menulis kode TypeScript yang tidak hanya fungsional, tetapi elegan dan aman jenisnya.

Tetap mengoding, tetap belajar, dan terutama, bersenang-senang dengan TypeScript!

Credits: Image by storyset