Generic функц
Өмнөх хичээлд generic-ийн үндсийг сурсан. Энэ хичээлд generic функцийг илүү хүчирхэг болгодог хоёр чухал онцлогийг сурна: хязгаарлалт (constraint) ба keyof оператор.
extends — төрлийн хязгаарлалт
Заримдаа T нь дурын биш, тодорхой шинж чанартай төрөл байхыг шаарддаг. extends ашиглан хязгаар тавина:
// Хязгаарлалтгүй — T.length гэж хандаж болохгүй
function уртыг_хэвлэх<T>(утга: T): void {
console.log(утга.length); // Алдаа: T дээр length байхгүй байж болно
}
// extends ашиглан зөвхөн length property-тэй төрлийг зөвшөөрнө
function уртыг_хэвлэх<T extends { length: number }>(утга: T): number {
return утга.length;
}
console.log(уртыг_хэвлэх("Монгол")); // 6 — string-д length байна ✅
console.log(уртыг_хэвлэх([1, 2, 3, 4])); // 4 — array-д length байна ✅
// уртыг_хэвлэх(42); // Алдаа: number-д length байхгүй ❌
T extends { length: number } нь "T нь дурын төрөл байж болох боловч заавал length гэсэн тоон property-тэй байх ёстой" гэсэн утгатай.
Жишээ: объектын шинж чанар авах
// T extends object — T нь заавал объект байх
function шинж_авах<T extends object>(объект: T, түлхүүр: keyof T): T[keyof T] {
return объект[түлхүүр];
}
const хэрэглэгч = { нэр: "Болд", нас: 25, хот: "Улаанбаатар" };
console.log(шинж_авах(хэрэглэгч, "нэр")); // "Болд"
console.log(шинж_авах(хэрэглэгч, "нас")); // 25
// шинж_авах(хэрэглэгч, "утас"); // Алдаа: "утас" энэ объектод байхгүй ❌
keyof — объектын түлхүүрүүдийн union
keyof нь объектын бүх property нэрийг union төрөл болгон гаргаж авдаг:
interface Хэрэглэгч {
нэр: string;
нас: number;
имэйл: string;
}
type ХэрэглэгчийнТүлхүүр = keyof Хэрэглэгч;
// "нэр" | "нас" | "имэйл"
// keyof-г generic-тэй хослуулах
function аюулгүй_авах<T, K extends keyof T>(объект: T, түлхүүр: K): T[K] {
return объект[түлхүүр];
}
const хэрэглэгч: Хэрэглэгч = { нэр: "Болд", нас: 25, имэйл: "bold@mail.com" };
const нэр: string = аюулгүй_авах(хэрэглэгч, "нэр"); // string ✅
const нас: number = аюулгүй_авах(хэрэглэгч, "нас"); // number ✅
K extends keyof T нь "K нь T-ийн аль нэг property нэр байх ёстой" гэсэн утгатай. Ингэснээр буцаах утгын төрөл T[K] болж, яг зөв төрлийг буцааж байгааг TypeScript мэддэг.
Default төрлийн параметр
Generic-д анхны утга өгч болно:
// T-д анхны утга — string
interface Жагсаалт<T = string> {
утгууд: T[];
нийт: number;
}
const мөрийн_жагсаалт: Жагсаалт = {
утгууд: ["а", "б", "в"],
нийт: 3,
};
const тооны_жагсаалт: Жагсаалт<number> = {
утгууд: [1, 2, 3],
нийт: 3,
};
Жагсаалт гэхэд TypeScript T = string гэж үзнэ. Тусгай төрөл хэрэгтэй бол Жагсаалт<number> гэж зааж өгнө.
Бодит жишээ: API хариуг боловсруулах функц
interface АПИХариу<T> {
өгөгдөл: T | null;
алдаа: string | null;
ачааллаж: boolean;
}
async function апи_дуудах<T>(url: string): Promise<АПИХариу<T>> {
try {
const хариу = await fetch(url);
const өгөгдөл: T = await хариу.json();
return { өгөгдөл, алдаа: null, ачааллаж: false };
} catch (алдаа) {
return { өгөгдөл: null, алдаа: "Алдаа гарлаа", ачааллаж: false };
}
}
// Хэрэглэгчийн мэдээлэл авах
interface Хэрэглэгч {
id: number;
нэр: string;
}
const хариу = await апи_дуудах<Хэрэглэгч>("/api/user/1");
// хариу.өгөгдөл нь Хэрэглэгч | null гэдгийг TypeScript мэднэ
Generic функц сурч дууссанаар API, utility, helper функцүүдийг хэдэн дахин дахин бичихгүйгээр нэг удаа зөв бичих боломжтой болно.
Дараагийн хичээлд:
Generic класс — классын property, method-д generic хэрхэн ашиглаж, дахин ашиглагдах өгөгдлийн бүтэц бүтээхийг сурна.