เจเนอริกใน TypeScript
บทความนี้อธิบายเกี่ยวกับเจเนอริกใน TypeScript
YouTube Video
เจเนอริกใน TypeScript
เจเนอริกใน TypeScript เป็นฟีเจอร์ที่ช่วยให้คุณกำหนดฟังก์ชัน คลาส และอินเทอร์เฟซที่นำกลับมาใช้ซ้ำได้และปลอดภัยด้วยการพารามิเตอร์ไทป์ การใช้เจเนอริกช่วยให้คุณเขียนโค้ดที่ไม่ได้ขึ้นอยู่กับประเภทที่เฉพาะเจาะจง ทำให้คุณสามารถดำเนินการแบบเดียวกันกับประเภทที่หลากหลาย
พื้นฐานของเจเนอริก
เจเนอริกทำหน้าที่เหมือนเท็มเพลตที่รับประเภทเป็นอาร์กิวเมนต์ ทำให้ฟังก์ชันและคลาสสามารถจัดการกับหลายประเภทได้
ฟังก์ชันเจเนอริก
ตัวอย่างต่อไปนี้เป็นฟังก์ชันที่ระบุประเภทของอาร์กิวเมนต์โดยใช้เจเนอริก
1function identity<T>(value: T): T {
2 return value;
3}
4
5console.log(identity<number>(42)); // 42
6console.log(identity<string>("Hello")); // Hello
T
เป็นอาร์กิวเมนต์ประเภทเจเนอริกที่แทนประเภทของอาร์กิวเมนต์และค่าที่ส่งคืนของฟังก์ชัน ประเภทที่แท้จริงจะถูกกำหนดเมื่อฟังก์ชันถูกเรียกใช้- ด้วยการระบุ
<number>
หรือ<string>
อย่างชัดเจน คุณกำลังระบุประเภท
ประเภทเจเนอริกทำงานได้โดยไม่ต้องระบุอย่างชัดเจน เนื่องจาก TypeScript จะทำการสรุปประเภทให้
1function identity<T>(value: T): T {
2 return value;
3}
4
5console.log(identity(42)); // 42
6console.log(identity("Hello")); // Hello
ข้อจำกัดของเจเนอริก
โดยการกำหนดข้อจำกัดให้เจเนอริก คุณสามารถจำกัดให้ยอมรับเฉพาะประเภทที่กำหนดได้เท่านั้น
1function loggingIdentity<T extends { length: number }>(arg: T): T {
2 console.log(arg.length);
3 return arg;
4}
5
6loggingIdentity("Hello"); // 5
7loggingIdentity([1, 2, 3]); // 3
8
9// loggingIdentity(42); // Error: number does not have a length property.
- การระบุ
T extends { length: number }
หมายความว่าT
ต้องเป็นประเภทที่มีคุณสมบัติlength
ดังนั้นประเภทที่ไม่มีคุณสมบัติlength
จะไม่ได้รับการยอมรับ
คลาสเจเนอริก
คลาสยังสามารถถูกกำหนดโดยใช้เจเนอริกได้ คลาสเจเนอริกมีความยืดหยุ่นในเรื่องของประเภทสำหรับคุณสมบัติและเมธอด
1class Box<T> {
2 private _value: T;
3
4 constructor(value: T) {
5 this._value = value;
6 }
7
8 public getValue(): T {
9 return this._value;
10 }
11
12 public setValue(value: T): void {
13 this._value = value;
14 }
15}
16
17const numberBox = new Box<number>(100);
18console.log(numberBox.getValue()); // 100
19
20const stringBox = new Box<string>("Hello");
21console.log(stringBox.getValue()); // Hello
Box<T>
ประกาศประเภทT
ที่ใช้ภายในคลาสเป็นเจเนอริก ช่วยให้คลาสเดียวกันสามารถนำกลับมาใช้กับประเภทที่แตกต่างกันได้
อินเทอร์เฟซเจเนอริก
เจเนอริกสามารถถูกใช้กับอินเทอร์เฟซได้เช่นกัน
1interface Pair<T, U> {
2 first: T;
3 second: U;
4}
5
6const numberStringPair: Pair<number, string> = { first: 1, second: "One" };
7console.log(numberStringPair); // { first: 1, second: 'One' }
8
9const booleanArrayPair: Pair<boolean, number[]> = { first: true, second: [1, 2, 3] };
10console.log(booleanArrayPair); // { first: true, second: [ 1, 2, 3 ] }
- โดยการระบุสองประเภทเจเนอริกด้วย
Pair<T, U>
คุณสามารถกำหนดวัตถุที่ผสมประเภทที่แตกต่างกันได้
อาร์กิวเมนต์ประเภทเริ่มต้น
นอกจากนี้ยังสามารถระบุประเภทเริ่มต้นสำหรับอาร์กิวเมนต์ประเภททั่วไปได้
1function createArray<T = string>(length: number, value: T): T[] {
2 return Array(length).fill(value);
3}
4
5console.log(createArray(3, "a")); // ['a', 'a', 'a']
6console.log(createArray(3, 100)); // [100, 100, 100]
- เรากำหนดอาร์กิวเมนต์ประเภทเริ่มต้นเป็น
string
ด้วย<T = string>
ถ้าไม่มีการระบุประเภทอย่างชัดเจนT
จะมีประเภทเป็นstring
ชื่อเรียกประเภททั่วไป
ประเภททั่วไปสามารถใช้เป็นชื่อเรียกประเภท (type
) ได้เช่นกัน
1type Result<T> = {
2 success: boolean;
3 data: T;
4};
5
6const successResult: Result<number> = { success: true, data: 42 };
7const errorResult: Result<string> = { success: false, data: "Error occurred" };
8
9console.log(successResult); // { success: true, data: 42 }
10console.log(errorResult); // { success: false, data: 'Error occurred' }
Result<T>
แทนวัตถุผลลัพธ์ที่มีข้อมูลของประเภทT
ด้วยวิธีนี้ คุณสามารถสร้างชื่อเรียกประเภทที่ยืดหยุ่นได้โดยใช้ประเภททั่วไป
ประเภททั่วไปหลายตัว
ด้วยการใช้ประเภททั่วไปหลายตัว คุณสามารถกำหนดฟังก์ชันและคลาสที่หลากหลายยิ่งขึ้น
1function merge<T, U>(obj1: T, obj2: U): T & U {
2 return { ...obj1, ...obj2 };
3}
4
5const person = { name: "Alice" };
6const job = { title: "Engineer" };
7
8const merged = merge(person, job);
9console.log(merged); // { name: 'Alice', title: 'Engineer' }
- ฟังก์ชัน
merge
รับประเภทสองประเภทที่แตกต่างกันT
และU
และรวมกันเพื่อนำกลับมาเป็นวัตถุใหม่
สรุป
- Generics ช่วยให้สร้างโค้ดที่นำกลับมาใช้ใหม่ได้และปลอดภัยในเรื่องประเภท โดยการพิจารณาประเภทเป็นพารามิเตอร์
- ด้วยการใช้ประเภททั่วไปใน ฟังก์ชัน คลาส และอินเตอร์เฟซ คุณสามารถเขียนตรรกะที่ยืดหยุ่นรองรับประเภทต่าง ๆ ได้
- ด้วยการเพิ่ม ข้อจำกัดไปยังอาร์กิวเมนต์ประเภท หรือกำหนด อาร์กิวเมนต์ประเภทเริ่มต้น คุณสามารถควบคุมขอบเขตของประเภททั่วไปได้
ด้วยการใช้ประเภททั่วไป คุณสามารถเขียนโค้ดที่ไม่ขึ้นกับประเภท มีวัตถุประสงค์ทั่วไป และใช้ประโยชน์จากระบบประเภทที่ทรงพลังของ TypeScript ได้อย่างสูงสุด
คุณสามารถติดตามบทความข้างต้นโดยใช้ Visual Studio Code บนช่อง YouTube ของเรา กรุณาตรวจสอบช่อง YouTube ด้วย