ป้ายกำกับ: เส้นรอบวง

TypeScript Generics คืออะไร? คู่มือเจาะลึกชนิดข้อมูลเจเนริกส์ใน TypeScript ฉบับเข้าใจง่ายTypeScript Generics คืออะไร? คู่มือเจาะลึกชนิดข้อมูลเจเนริกส์ใน TypeScript ฉบับเข้าใจง่าย

สำหรับนักพัฒนาที่ทำงานกับระบบขนาดใหญ่และต้องการความยืดหยุ่นของโค้ดสูง การรักษาคุณสมบัติ ‘Type Safety’ (ความปลอดภัยของประเภทตัวแปร) ถือเป็นหัวใจสำคัญของ TypeScript แต่บ่อยครั้งที่เราต้องเผชิญกับสถานการณ์ที่ต้องการสร้างฟังก์ชันหรือคลาสที่สามารถทำงานกับชุดข้อมูลได้หลากหลายประเภท โดยที่ไม่จำเป็นต้องระบุชื่อ Type นั้นอย่างตายตัว

นี่คือจุดที่ Generics เข้ามามีบทบาทสำคัญ Generics ไม่ใช่แค่คุณสมบัติทางไวยากรณ์ แต่เป็นหลักการเชิงสถาปัตยกรรม (Architectural Pattern) ที่ช่วยให้เราสามารถออกแบบโค้ดให้มีความยืดหยุ่น (Reusability) สูงสุด โดยที่ยังคงรักษาความแม่นยำของ Type Safety ไว้ได้อย่างสมบูรณ์แบบที่สุด

💡 Generics คืออะไร? หลักการทำงานในมุมมองของสถาปนิก

ในทางเทคนิค Generics คือการใช้ Type Parameter (ตัวแปรประเภท) ในการกำหนด Type ของฟังก์ชัน, คลาส, หรือ Interface มันทำหน้าที่เป็นตัวแทนของ Type ที่จะถูกระบุเมื่อมีการเรียกใช้งานจริง หากเปรียบเทียบ Generics เหมือนการสร้าง ‘แม่พิมพ์’ ที่มีช่องว่างไว้สำหรับใส่ Type ต่างๆ เมื่อเราใช้งานจริง เราก็จะใส่ Type ที่ต้องการลงไปในช่องว่างนั้น ทำให้โค้ดของเราสามารถทำงานได้กับทั้ง Array ของ String, Array ของ Number, หรือ Object ที่มีโครงสร้างเฉพาะ โดยที่ Compiler ยังคงรู้ว่าข้อมูลที่ส่งเข้ามาและส่งออกไปนั้นมี Type ที่สอดคล้องกันเสมอ

✨ ตัวอย่างการใช้งาน Generics ใน TypeScript

สมมติว่าเราต้องการสร้างฟังก์ชันที่รับ Array ของข้อมูลใดๆ เข้ามา และส่งคืนข้อมูลนั้นกลับไป โดยที่ฟังก์ชันนี้ต้องทำงานได้ไม่ว่าข้อมูลนั้นจะเป็น String หรือ Number เราจะใช้ Generics เข้ามาช่วย:

TypeScript

// การใช้ Generics <T> เพื่อระบุ Type ที่ยืดหยุ่น
function identity<T>(arg: T): T {
    // ฟังก์ชันนี้รับค่าใดๆ (T) และคืนค่ากลับมาเป็น Type เดียวกัน (T)
    return arg;
}

// ตัวอย่างการใช้งานจริง (TypeScript จะระบุ Type ให้โดยอัตโนมัติ)
let stringResult = identity('apple,banana,orange') as string;
let numberResult = identity(1, 2, 3) as number;

// Compiler รับประกันว่า stringResult ต้องเป็น string เสมอ
// stringResult.toFixed(2); // Error: 'string' does not have 'toFixed'

🚀 การยกระดับความเข้าใจ: Type Constraints

ในระดับ Senior Architect เราไม่เพียงแค่ใช้ Generics แต่เรายังต้องมีการจำกัด Type (Type Constraints) เพื่อให้มั่นใจว่า Type Parameter ที่เราใช้จะมีความสามารถบางอย่างที่เราต้องการ เช่น หากเราสร้างฟังก์ชันที่ต้องรับ Object ที่มีคุณสมบัติ ‘id’ เสมอ เราสามารถใช้ extends เพื่อบังคับให้ Type นั้นต้องมีคุณสมบัติเหล่านั้นได้

TypeScript

interface HasId { 
    id: number; 
}

// <T extends HasId> บังคับว่า Type T ต้องมีคุณสมบัติ 'id' เป็น number
function getById<T extends HasId>(item: T): number {
    return item['id'];
}

// ตัวอย่างการใช้งาน: ต้องส่ง Object ที่มี 'id' เท่านั้น
const user = { id: 101, name: 'Alice' };
let userId = getById(user);

✅ สรุป: Generics คือกุญแจสู่ความยืดหยุ่นที่ปลอดภัย

Generics คือเครื่องมือที่ทรงพลังที่สุดชิ้นหนึ่งใน TypeScript มันช่วยให้เราสามารถเขียนโค้ดที่สามารถนำกลับมาใช้ใหม่ได้สูง (Highly Reusable) โดยที่ไม่ต้องแลกมาด้วยการสูญเสียคุณสมบัติ Type Safety ไปเลย การทำความเข้าใจ Generics และการใช้ Type Constraints อย่างถูกต้อง จะช่วยยกระดับโค้ดเบสของคุณให้มีความเป็นระเบียบ, บำรุงรักษาง่าย, และมีประสิทธิภาพสูงตามมาตรฐานของ Senior Architect อย่างแท้จริง