Skip to content
GitHub

Generic များကို ထိန်းချုပ်ခြင်း: ကန့်သတ်ချက်များ (Constraints)

အဓိက ပြဿနာ: Generic တွေက တစ်ခါတလေ လိုက်လျောညီထွေ ရှိလွန်းနေခြင်း

Section titled “အဓိက ပြဿနာ: Generic တွေက တစ်ခါတလေ လိုက်လျောညီထွေ ရှိလွန်းနေခြင်း”

Generic တွေမှာ T ဆိုတာ ဘာ Type မဆို ဖြစ်လို့ရတယ်ဆိုတဲ့အတွက် တကယ် အစွမ်းထက်ပါတယ်။ ဒါပေမဲ့ တစ်ခါတလေကျတော့ အဲ့ဒီလို လိုက်လျောညီထွေ ရှိလွန်းတာကြီးကပဲ ပြဿနာ ပြန်ဖြစ်တတ်ပါတယ်။ ဥပမာ - ကျွန်တော်တို့ရဲ့ Generic Function ထဲမှာ Parameter အနေနဲ့ လက်ခံရရှိတဲ့ Data ရဲ့ Property တစ်ခုခုကို အသုံးပြုချင်တယ်ဆိုပါစို့။

ဥပမာအနေနဲ့ - လက်ခံရရှိတဲ့ Data ရဲ့ Length ကို Console မှာ ထုတ်ပြမယ့် Function လေးတစ်ခုကို ရေးကြည့်ရအောင်။

index.ts
function logLength<T>(arg: T): void {
// TypeScript က ဒီနေရာမှာ Error ပြလိမ့်မယ်!
// console.log(arg.length); // ERROR: Property 'length' does not exist on type 'T'.
}

ဒီနေရာမှာ TypeScript က မှန်မှန်ကန်ကန်ပဲ Error ပြပေးပါတယ်။ ဘာလို့လဲဆိုတော့ T က ဘာ Type မဆို ဖြစ်နိုင်လို့ပါပဲ။ တကယ်လို့ တစ်ယောက်ယောက်က logLength(123) လို့ Number ထည့်ပြီး ခေါ်လိုက်ရင် ဘာဖြစ်မလဲ? number Type တွေမှာ .length ဆိုတဲ့ Property မှ မရှိတာ။ ဒါမှမဟုတ် logLength({ name: 'Bob' }) လို့ ခေါ်ရင်ရော? အဲ့ဒီ Object မှာလည်း .length ဆိုတာ မရှိပါဘူး။ ဒီလိုမျိုး T က တကယ့်ကို ဘာမဆို ဖြစ်နိုင်နေရင် ကျွန်တော်တို့ရဲ့ Function က Type Safety (စိတ်ချရမှု) မရှိတော့ပါဘူး။

ဖြေရှင်းနည်း: extends ကို အသုံးပြု၍ ကန့်သတ်ခြင်း (Constraints)

Section titled “ဖြေရှင်းနည်း: extends ကို အသုံးပြု၍ ကန့်သတ်ခြင်း (Constraints)”

ဒီတော့ ကျွန်တော်တို့ TypeScript ကို သေချာ ပြောပြဖို့ လိုလာပါပြီ။ “အိုကေ၊ T က Flexible ဖြစ်ပါစေ၊ ဒါပေမဲ့ သူဟာ length ဆိုတဲ့ Property တစ်ခုတော့ မဖြစ်မနေ ပါကို ပါဝင်ရမယ် (ပြီးတော့ အဲ့ဒီ Property က number Type ဖြစ်သင့်တယ်)” လို့ တိတိကျကျ သတ်မှတ်ပေးရပါမယ်။

ဒီလို သတ်မှတ်တာကို Generic ကြေညာတဲ့နေရာမှာ extends Keyword ကို အသုံးပြုပြီး လုပ်ဆောင်ပါတယ်။

index.ts
// ကျွန်တော်တို့ လိုအပ်တဲ့ Property ရှိကြောင်း ဖော်ပြမယ့် Interface လေးတစ်ခု အရင်သတ်မှတ်မယ်
interface Lengthwise {
length: number;
}
// T ကို ကန့်သတ်လိုက်မယ်: T ဟာ Lengthwise Interface မှာ ရှိတဲ့ Property တွေ ပါကို ပါဝင်ရမယ်
function logLength<T extends Lengthwise>(arg: T): void {
// အခုဆိုရင် TypeScript က arg မှာ .length ဆိုတဲ့ Property ရှိကြောင်း သေချာ သိသွားပြီ!
console.log(`Length: ${arg.length}`);
}

ကန့်သတ်ထားသော Generic များကို အသုံးပြုခြင်း

Section titled “ကန့်သတ်ထားသော Generic များကို အသုံးပြုခြင်း”

ဒီလိုမျိုး ကန့်သတ်ချက် (Constraint) ထည့်လိုက်တော့ ကျွန်တော်တို့ရဲ့ Function က ကန့်သတ်ချက်နဲ့ ကိုက်ညီတဲ့ Type တွေနဲ့ စိတ်ချယုံကြည်စွာ အလုပ်လုပ်နိုင်သွားပါပြီ။

index.ts
logLength("Hello TypeScript!"); // အလုပ်လုပ်တယ် (string မှာ length ရှိလို့ပါ)
logLength([1, 2, 3, 4]); // အလုပ်လုပ်တယ် (array မှာ length ရှိလို့ပါ)
logLength({ length: 10, value: "Data" }); // အလုပ်လုပ်တယ် (ဒီ object မှာ length property ပါဝင်လို့ပါ)
// logLength(123); // ERROR: number Type ဟာ Lengthwise Type နဲ့ မကိုက်ညီဘူးလို့ TypeScript က Error ပြပါမယ်။
// logLength({ name: "No length" }); // ERROR: length Property ပျောက်နေတယ်လို့ Error ပြပါမယ်။
// logLength({}); // ERROR: length Property ပျောက်နေတယ်လို့ Error ပြပါမယ်။

တစ်ခါတလေကျတော့ သီးခြား Interface တစ်ခု အသစ် သတ်မှတ်ဖို့တောင် မလိုပါဘူး။ တခြား ရှိပြီးသား Type တစ်ခုရဲ့ ပုံစံ (Shape) အတိုင်း တိုက်ရိုက် ကန့်သတ်လို့ ရပါတယ်။ keyof T လိုမျိုး Keyword တွေကို သုံးတာပေါ့။ keyof T ဆိုတာက T Type မှာရှိတဲ့ Property နာမည်တွေ အကုန်လုံး (Keys တွေ) ကို စုစည်းပြီး ပြောတာပါ။

index.ts
// T က မည်သည့် Object Type မဆို ဖြစ်ရမယ်၊ K ကတော့ T ရဲ့ Property နာမည်တွေထဲက တစ်ခုခု ဖြစ်ရမယ်လို့ သတ်မှတ်လိုက်တာပါ
function getProperty<T extends object, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key]; // obj ထဲက key ဆိုတဲ့ Property ရဲ့ တန်ဖိုးကို ပြန်ထုတ်ပေးမယ်
}
let user = { name: "Alice", age: 30 }; // user ရဲ့ Type က { name: string; age: number; }
// user object ထဲက "name" ဆိုတဲ့ Property ကို ယူမယ်
let userName = getProperty(user, "name"); // အလုပ်လုပ်တယ်! K က "name" ဖြစ်သွားပြီး၊ T က user ရဲ့ Type ပါ
console.log(userName); // Output: Alice
// user object ထဲက မရှိတဲ့ "address" ဆိုတဲ့ Property ကို ယူကြည့်မယ်
// let userAddress = getProperty(user, "address"); // ERROR: "address" ဆိုတာ user ရဲ့ Property နာမည်တွေ ("name" | "age") ထဲမှာ မပါဘူးလို့ TypeScript က ကြိုတင် Error ပြပါပြီ။

ဒီလို သတ်မှတ်လိုက်တော့ getProperty Function ကို ခေါ်တဲ့အခါ obj ဆိုတဲ့ Object ရယ်၊ အဲ့ဒီ Object ထဲမှာ တကယ်ရှိနေတဲ့ Property ရဲ့ နာမည် (Key) ရယ်ကိုပဲ လက်ခံပါတော့တယ်။ မရှိတဲ့ Property နာမည်ကို ထည့်ခေါ်ရင် Code ရေးနေတုန်းမှာတင် (Editor ထဲမှာတင်) TypeScript က Error ပြပေးပါတယ်။ ပြန်ထွက်လာမယ့် Data ရဲ့ Type ကလည်း T[K] (ဆိုလိုတာက T ထဲက K ဆိုတဲ့ Property ရဲ့ Type အစစ်) လို့ အတိအကျ သိရှိနိုင်ပါတယ်။