ป้ายกำกับ: Cooling System

TypeScript: ตรวจสอบข้อผิดพลาดจาก PromiseTypeScript: ตรวจสอบข้อผิดพลาดจาก Promise

ในโลกของการพัฒนาแอปพลิเคชันสมัยใหม่ การจัดการกับงานที่ไม่พร้อมกัน (Asynchronous Operations) ถือเป็นหัวใจสำคัญ ไม่ว่าจะเป็นการเรียก API จากเซิร์ฟเวอร์, การอ่านข้อมูลจากฐานข้อมูล PostgreSQL, หรือแม้แต่การทำ Timeouts ทั้งหมดเหล่านี้ล้วนต้องพึ่งพากลไกของ Promises ซึ่งช่วยให้โค้ดของเราสามารถไหลได้อย่างมีระเบียบ แม้ว่าจะมีการทำงานที่ล่าช้าก็ตาม

เมื่อเราใช้ TypeScript ร่วมกับฐานข้อมูล PostgreSQL ในสภาพแวดล้อม Node.js การรับส่งข้อผิดพลาด (Error Handling) ที่แข็งแกร่งจึงเป็นสิ่งจำเป็นอย่างยิ่งยวด เราไม่สามารถปล่อยให้ข้อผิดพลาดในการเชื่อมต่อหรือการ Query ถูกมองข้ามไปได้ เพราะมันอาจนำไปสู่ข้อมูลที่ไม่ถูกต้องหรือการล่มของระบบได้

หลักการพื้นฐาน: ความเปราะบางของการทำ Asynchronicity

Promises ถูกออกแบบมาเพื่อแก้ปัญหา Callback Hell โดยกำหนดสถานะสามประการ คือ Pending (กำลังรอคอย), Resolved (สำเร็จแล้ว), และ Rejected (ล้มเหลวหรือเกิดข้อผิดพลาดขึ้น) ในภาษา JavaScript/TypeScript ทั่วไป เราจะอาศัยเมธอด .catch() หรือโครงสร้าง try...catch ร่วมกับ async/await เพื่อจับภาพ Promise Rejection เสมือนเครือข่ายป้องกัน

TypeScript กับการรับประกันความปลอดภัยของข้อมูล (Type Safety)

จุดเด่นที่ TypeScript เข้ามาเสริมคือการบังคับใช้คุณสมบัติเชิงประเภท (Type System) เมื่อเราเขียนโค้ดที่เกี่ยวข้องกับฐานข้อมูล PostgreSQL เราสามารถกำหนด Type ให้กับผลลัพธ์ที่คาดหวัง (เช่น PostgresRecord[]) และที่สำคัญกว่านั้นคือการกำหนด Type ให้กับข้อผิดพลาดที่อาจเกิดขึ้น (Error) ทำให้เราสามารถเขียนโค้ดที่ตรวจสอบข้อผิดพลาดได้อย่างแม่นยำและลดโอกาสเกิด Runtime Error ได้อย่างมาก

ตัวอย่าง: การจัดการข้อผิดพลาดในการ Query PostgreSQL

สมมติว่าเรามีฟังก์ชันที่ต้องดึงข้อมูลจาก PostgreSQL โดยใช้ไลบรารีที่รองรับ Promises (เช่น pg) เราจะต้องห่อหุ้มการเรียกใช้ Query ไว้ใน try...catch เพื่อให้มั่นใจว่าไม่ว่า Query จะล้มเหลวด้วยสาเหตุใด (เช่น Syntax Error หรือ Connection Failure) เราก็สามารถจัดการมันได้อย่างเป็นระบบ

TypeScript

// สมมติว่าเราใช้ไลบรารี pg ใน Node.js/TypeScript

async function getProductsFromDB(productIds: string[]): Promise<any[]> {
    const client = await connectToPostgres(); // ฟังก์ชันจำลองการเชื่อมต่อ
    try {
        // 1. สร้าง Query ที่ปลอดภัย (ใช้ $1, $2... เพื่อป้องกัน SQL Injection)
        const queryText = "SELECT * FROM products WHERE id = ANY($1)";
        
        // 2. เรียกใช้ Query และรอผลลัพธ์
        const result = await client.query(queryText, [productIds]);
        
        // 3. ส่งคืนข้อมูลที่สำเร็จ
        return result.rows;

    } catch (error) {
        // 4. ส่วนสำคัญ: การจับข้อผิดพลาด (Promise Rejection)
        console.error("🚨 Database Query Failed: ", error);
        
        // 5. การโยนข้อผิดพลาดที่ถูกจัดการแล้ว (Re-throw) เพื่อให้ส่วนเรียกใช้ทราบ
        // เราสามารถแปลง error ให้เป็น Custom Error เพื่อให้ caller จัดการได้ง่ายขึ้น
        throw new Error("Failed to fetch product data from PostgreSQL.");
    } finally {
        client.release(); // ปล่อยทรัพยากรเสมอ ไม่ว่าจะสำเร็จหรือไม่
    }
}

// ตัวอย่างการเรียกใช้ที่สมบูรณ์
async function runExample() {
    try {
        const products = await getProductsFromDB(['1', '2', '3']);
        console.log("✅ Success: Fetched products:", products);
    } catch (e) {
        // ส่วนนี้จะรับข้อผิดพลาดที่ถูก throw ออกมาจาก getProductsFromDB
        console.log("❌ Application Error Handled: Cannot proceed due to DB failure.");
    }
}

runExample();

บทสรุป: ความสมบูรณ์แบบของการจัดการ Error

การใช้ TypeScript ในการพัฒนาแอปพลิเคชันที่เชื่อมต่อกับ PostgreSQL ไม่ได้หมายถึงแค่การป้องกัน Type Mismatch เท่านั้น แต่ยังรวมถึงการสร้างระบบที่ทนทาน (Resilient) ในการจัดการ Asynchronous Operations ด้วย การใช้โครงสร้าง try...catch ร่วมกับ async/await และการกำหนด Type อย่างชัดเจน ทำให้เราสามารถควบคุม Flow ของโปรแกรมได้อย่างสมบูรณ์ ไม่ว่าการเชื่อมต่อจะล้มเหลว หรือ Query จะมี Syntax Error ระบบของเราก็สามารถจับข้อผิดพลาดเหล่านั้นได้อย่างเป็นระบบ และส่งคืนสถานะที่ถูกต้องไปยังผู้ใช้หรือระบบเรียกใช้ต่อไป