Generics တွေရဲ့ အသုံးဝင်ပုံ - Functions, Interfaces, Classes တွေမှာ သုံးခြင်း
Generic Functions
Section titled “Generic Functions”Generics က ခုနက ပြောခဲ့တဲ့ Identity Function လို ရိုးရိုးလေးတွေတင်မကပါဘူး။ တခြား Function အမျိုးမျိုးမှာလည်း သုံးလို့ရတယ်။ ဥပမာအနေနဲ့ Data တစ်ခုခုကို လက်ခံပြီး အဲဒီ Data တစ်ခုတည်း ပါဝင်တဲ့ array တစ်ခု ပြန်ထုတ်ပေးမယ့် Function လေးတစ်ခု ရေးကြည့်ရအောင်။
// Generic Type Variable <T> ကို သုံးမယ်function wrapInArray<T>(input: T): T[] { return [input];}
// wrapInArray Function ကို သုံးကြည့်မယ်let numberArray = wrapInArray(10); // 10 ဆိုတဲ့ number ထည့်လိုက်တော့ T က number လို့ မှန်းသိတယ်၊ ပြန်ထွက်တဲ့ Type က number[] ဖြစ်သွားတယ်console.log(numberArray); // Output: [10]
let stringArray = wrapInArray("World"); // "World" ဆိုတဲ့ string ထည့်လိုက်တော့ T က string ဖြစ်သွားတယ်၊ ပြန်ထွက်တဲ့ Type က string[] ဖြစ်သွားတယ်console.log(stringArray); // Output: ["World"]
let userObject = { id: 1, name: "Admin" };let userArray = wrapInArray(userObject); // { id: number; name: string; } ဆိုတဲ့ object ထည့်လိုက်တော့ T က အဲဒီ object Type ဖြစ်သွားတယ်၊ ပြန်ထွက်တဲ့ Type က အဲဒီ object Type ရဲ့ array[] ဖြစ်သွားတယ်console.log(userArray); // Output: [{ id: 1, name: "Admin" }]
Generic Interfaces
Section titled “Generic Interfaces”Interfaces တွေက object တွေရဲ့ ပုံစံ (shape) ကို သတ်မှတ်ပေးတယ်ဆိုတာ သိထားပြီးသားနော်။ ဒီ Interface တွေရဲ့ ပုံစံကိုလည်း Generics သုံးပြီး ပိုပြီး လိုက်လျောညီထွေ ဖြစ်အောင် လုပ်လို့ရတယ်။ API ကနေ ပြန်လာတဲ့ Response တွေအတွက် Standard ပုံစံတစ်ခု သတ်မှတ်တာက Generic Interface ရဲ့ အကောင်းဆုံး ဥပမာတစ်ခုပဲ။
// ApiResponse ဆိုတဲ့ Interface ကို Generic ဖြစ်အောင် လုပ်မယ်// <DataType> ဆိုတာ ကျွန်တော်တို့ရဲ့ Generic Type Variable ပေါ့interface ApiResponse<DataType> { data: DataType; // API ကနေ ပြန်လာမယ့် တကယ့် Data ရဲ့ Type က ဒီ DataType ပဲ success: boolean; // အောင်မြင်လား မအောင်မြင်ဘူးလား timestamp: Date; // ဘယ်အချိန်လဲ error?: string; // Error ရှိရင် စာသားပြမယ် (ပါချင်မှ ပါမယ်)}
// ဒီ Generic Interface ကို ဘယ်လို သုံးမလဲ ကြည့်ရအောင်interface User { id: number; username: string; } // User Object ရဲ့ ပုံစံinterface Product { sku: string; price: number; name: string; } // Product Object ရဲ့ ပုံစံ
// API ကနေ User တစ်ယောက်ရဲ့ Data ပြန်လာမယ်ဆိုရင် ApiResponse<User> လို့ သုံးမယ်let userResponse: ApiResponse<User> = {data: { id: 1, username: "ts_fan" }, // data ရဲ့ Type က User ဖြစ်ရမယ်success: true,timestamp: new Date()};
// API ကနေ Product တွေရဲ့ Array ပြန်လာမယ်ဆိုရင် ApiResponse<Product[]> လို့ သုံးမယ်let productsResponse: ApiResponse<Product[]> = {data: [ // data ရဲ့ Type က Product Array ဖြစ်ရမယ်{ sku: "TSHIRT01", price: 25.99, name: "TypeScript Logo Tee" },{ sku: "MUG004", price: 12.50, name: "Generic Mug" }],success: true,timestamp: new Date()};
// ဒီလို သုံးလိုက်တော့ TypeScript က data ထဲမှာ ဘာ Type ရှိလဲဆိုတာ သိနေပြီconsole.log(userResponse.data.username); // data က User ဖြစ်လို့ username ကို သုံးလို့ရတယ်console.log(productsResponse.data[0].price); // data က Product[] ဖြစ်လို့ data[0] က Product တစ်ခု ဖြစ်မယ်၊ သူ့ရဲ့ price ကို သုံးလို့ရတယ်
Generic Classes
Section titled “Generic Classes”Classes တွေမှာလည်း Generics ကို သုံးလို့ရတယ်။ ဥပမာအားဖြင့် Data တွေကို အစီအစဉ်အတိုင်း ထည့်သွင်းပြီး နောက်ဆုံးမှ ထည့်တဲ့ Data ကို အရင်ဆုံး ပြန်ထုတ်ယူရတဲ့ Data Structure တစ်ခုဖြစ်တဲ့ Stack (Last-In, First-Out) ရိုးရိုးလေးတစ်ခုကို Class နဲ့ တည်ဆောက်ကြည့်ရအောင်။
// Stack Class ကို Generic ဖြစ်အောင် <ElementType> သုံးလိုက်မယ်// ဒီ Stack ထဲမှာ ဘယ် Type က Data တွေ ထည့်မလဲဆိုတာ ElementType က သတ်မှတ်ပေးမယ်class Stack<ElementType> {// ဒီ Stack ထဲက data တွေကို ထိန်းသိမ်းမယ့် arrayprivate items: ElementType[] = [];
// Stack ထဲကို Data ထည့်မယ့် Functionpush(item: ElementType): void { // ထည့်မယ့် item ရဲ့ Type က Stack ရဲ့ ElementType ဖြစ်ရမယ်this.items.push(item);}
// Stack ထဲက နောက်ဆုံး Data ကို ပြန်ထုတ်မယ့် Functionpop(): ElementType | undefined { // ပြန်ထွက်လာမယ့် Data ရဲ့ Type က Stack ရဲ့ ElementType ပဲ ဖြစ်မယ်၊ ဒါမှမဟုတ် ဘာမှ မရှိရင် undefinedreturn this.items.pop();}
// Stack ထဲက နောက်ဆုံး Data ကို ကြည့်မယ့် Function (ထုတ်ယူခြင်းမရှိ)peek(): ElementType | undefined { // Type က pop လိုပဲreturn this.items[this.items.length - 1];}}
// အခု ဒီ Generic Stack Class ကို သုံးပြီး Stack Object တွေ ဖန်တီးကြည့်မယ်// number တွေပဲ ထည့်လို့ရမယ့် Stack တစ်ခု ဖန်တီးမယ်let numberStack = new Stack<number>(); // Stack<number> လို့ သတ်မှတ်လိုက်တော့ ElementType က number ဖြစ်သွားပြီ
numberStack.push(10); // number ထည့်လို့ရတယ်numberStack.push(20); // number ထပ်ထည့်လို့ရတယ်
let lastNumber = numberStack.pop(); // pop လုပ်လိုက်ရင် number | undefined ပြန်ထွက်မယ်။ တကယ်တော့ 20 (number) ပြန်ထွက်တယ်console.log(lastNumber); // Output: 20
// string တွေပဲ ထည့်လို့ရမယ့် Stack တစ်ခု ဖန်တီးမယ်let stringStack = new Stack<string>(); // Stack<string> လို့ သတ်မှတ်လိုက်တော့ ElementType က string ဖြစ်သွားပြီ
stringStack.push("first"); // string ထည့်လို့ရတယ်stringStack.push("second"); // string ထပ်ထည့်လို့ရတယ်
let lastString = stringStack.pop(); // pop လုပ်လိုက်ရင် string | undefined ပြန်ထွက်မယ်။ တကယ်တော့ "second" (string) ပြန်ထွက်တယ်console.log(lastString); // Output: "second"
// stringStack.push(123); // ERROR: stringStack က string တွေအတွက် Stack ဖြစ်လို့ number လာထည့်လို့ မရဘူး။ TypeScript က Error ပြပြီ!
Class ထဲက Method တွေဖြစ်တဲ့ push, pop, peek တွေ အားလုံးကလည်း အဲဒီ သတ်မှတ်လိုက်တဲ့ ElementType Type အတိုင်းပဲ အလုပ်လုပ်တော့ Type Safety ကို သေချာစေတယ်။ numberStack ထဲကို string သွားထည့်လို့ မရဘူး၊ stringStack ထဲကို number သွားထည့်လို့ မရဘူး။ ဒါကြောင့် Code တွေ ပိုစိတ်ချရပြီး ပြန်သုံးရ ပိုလွယ်လာတာပေါ့။