TypeScript Advanced Patterns yang Wajib Dikuasai
TypeScript bukan sekadar JavaScript dengan type annotation. Ada sejumlah pola lanjutan yang — ketika dikuasai — akan mengubah cara kamu menulis kode secara fundamental.
1. Conditional Types
Conditional types memungkinkan kamu membuat tipe yang bergantung pada kondisi tipe lain. Sintaksnya mirip ternary operator dan sangat powerful untuk utility types.
type IsString<T> = T extends string ? "ya, string" : "bukan string";
type A = IsString<string>; // "ya, string"
type B = IsString<number>; // "bukan string"
// Ekstrak tipe dari Promise
type Awaited<T> = T extends Promise<infer U> ? U : T;
async function fetchUser() {
return { id: 1, name: "Budi" };
}
type UserType = Awaited<ReturnType<typeof fetchUser>>;
// { id: number; name: string }2. Template Literal Types
TypeScript 4.1+ mendukung template literal types — kombinasi string literal yang sangat powerful untuk mendefinisikan string patterns secara type-safe.
type Direction = "top" | "right" | "bottom" | "left";
type Margin = `margin-${Direction}`;
// "margin-top" | "margin-right" | "margin-bottom" | "margin-left"
type EventName = "click" | "focus" | "blur";
type HandlerName = `on${Capitalize<EventName>}`;
// "onClick" | "onFocus" | "onBlur"3. Discriminated Unions untuk State Management
Pola ini sangat berguna untuk mengelola state yang memiliki bentuk berbeda-beda, misalnya state API call yang bisa idle, loading, success, atau error.
type AsyncState<T> =
| { status: "idle" }
| { status: "loading" }
| { status: "success"; data: T }
| { status: "error"; error: Error };
function DataDisplay({ state }: { state: AsyncState<User[]> }) {
switch (state.status) {
case "idle": return <p>Belum ada data</p>;
case "loading": return <Spinner />;
case "success": return <UserList users={state.data} />;
case "error": return <ErrorMessage msg={state.error.message} />;
}
}4. Satisfies Operator (TS 4.9+)
Operator satisfies memungkinkan kamu memvalidasi tipe tanpa kehilangan informasi tipe yang lebih spesifik. Ini salah satu fitur paling berguna di TypeScript modern.
type Color = string | RGB;
type RGB = [number, number, number];
// ❌ Dengan annotation biasa — kehilangan info spesifik
const palette: Record<string, Color> = {
red: [255, 0, 0],
green: "#00ff00",
};
palette.red.toUpperCase(); // Error: Color mungkin bukan string
// ✅ Dengan satisfies — tipe spesifik dipertahankan!
const palette2 = {
red: [255, 0, 0],
green: "#00ff00",
} satisfies Record<string, Color>;
palette2.red[0]; // ✅ TypeScript tahu ini array
palette2.green.toUpperCase(); // ✅ TypeScript tahu ini string