– Error Handling เป็นเรื่องใหญ่ เพราะในซอฟต์แวร์จริง ทุกอย่างมีโอกาสผิดพลาด เช่น network ล่ม, ข้อมูลไม่ครบ ฯลฯ
.
– การจัดการ error ที่ดีจะช่วยให้แอปไม่ crash เฉย ๆ แต่แจ้ง error ที่เข้าใจง่ายกับผู้ใช้ และ log ข้อมูลที่เป็นประโยชน์กับ dev
.
– พื้นฐานของ Error Handling ใน JavaScript
เครื่องมือหลักคือ try…catch, throw และ Error object
.
– Error ที่ไม่ถูก catch จะ “bubble” (ลอยขึ้นบน) ไปถึง global scope แล้วทำให้แอปหยุดหรือแสดง warning
.
– ถ้าเป็น async (Promise/async-await) ก็ใช้ .catch() หรือใส่ try…catch รอบ await
.
– ข้อควรระวังและจุดอ่อนของ JavaScript
JS สามารถ throw อะไรก็ได้ (string, number, object…) ไม่จำเป็นต้องเป็น Error ทำให้ใน catch อาจจะเจออะไรก็ได้ ต้องตรวจสอบเอง
.
– TypeScript ก็ช่วยไม่ได้มาก เพราะไม่สามารถรู้ได้ว่า error ที่ throw จะเป็นชนิดอะไร ต้องใช้ unknown หรือ any
.
– หลาย ๆ ไลบรารี (เช่น Supabase) เปลี่ยนจาก throw มาเป็น return object ที่มี error property แทน ซึ่งควบคุมได้ง่ายกว่า
.
– โค้ด Utility ง่าย ๆ ที่ใช้ได้จริง (ดีและ practical สำหรับโปรเจกต์ JavaScript/TypeScript ทั่วไป)
parseError: รับ error (unknown) แล้ว return เป็นข้อความ string ที่อ่านเข้าใจง่ายเสมอ ตัวอย่างโค้ด
export const parseError = (error: unknown) => {
if (typeof error === ‘string’) {
return error;
}
if (error instanceof Error) {
return error.message;
}
return ‘An error occurred’;
};
handleError: เรียก parseError แล้วเอาไปโชว์ toast/error UI (หรือจะ log ก็ได้) ตัวอย่างโค้ด
import { toast } from ‘sonner’;
import { parseError } from ‘./parse’;
export const handleError = (title: string, error: unknown) => {
const description = parseError(error);
toast.error(title, { description });
};
ตัวอย่าง การใช้กับ try / catch
import { handleError } from ‘@/lib/error/handle’;
try {
throw new Error(‘Something went wrong’);
} catch (err) {
handleError(‘Something went wrong’, err);
}
.
ตัวอย่างการใช้กับ promise chains
import { handleError } from ‘@/lib/error/handle’;
fetch(‘https://api.example.com/data‘)
.then((response) => response.json())
.then(console.log)
.catch(handleError);
.
– ความคิดเห็นจาก dev สายต่าง ๆ
1. Just Use Try/Catch
หลายคนบอกว่า try/catch ธรรมดาก็พอแล้ว
ส่วนมากนิยมจับ error แค่ในจุดบน ๆ ของแอป เช่น React Error Boundary หรือ Express middleware แล้วให้ error bubble ขึ้นมา
2. neverthrow
ไลบรารีที่เอา pattern แบบ Rust (Result/Ok/Err) มาใช้ใน TypeScript
ทุก function จะ return ว่าผ่าน/ไม่ผ่านแบบชัดเจน ต้อง handle error case ทุกครั้ง
ปลอดภัย, type-safe, explicit แต่โค้ดจะ verbose ขึ้น และมี dependency
3. Effect
เป็น functional effect system ที่จัดการ error, async, dependency ฯลฯ แบบ Haskell/Scala
Error type ถูก track ใน type system – ไม่ handle ครบ, โค้ดไม่ compile
เหมาะกับโค้ดฐานใหญ่ ๆ, ต้องการความ robust, แต่ “หนัก” มาก ไม่เหมาะเอามาใส่เล่น ๆ
ทำไมถกกันไม่จบ?
JavaScript ยืดหยุ่นสูง throw อะไรก็ได้ ไม่ force dev ให้ระบุ error ชนิดไหน
TypeScript ก็ไม่ได้ช่วยด้านนี้มากนัก เพราะทีมงานคิดว่าไม่เหมาะจะใส่ checked exception/throws keyword ในภาษา
สุดท้าย ไม่มีวิธีไหน “ถูก” หรือ “ผิด” เสียทีเดียว
.
ข้อแนะนำสรุปสำหรับ dev
1. เริ่มจากพื้นฐาน ใช้ try/catch ให้ถูกที่ อย่าปล่อยให้ error เงียบ
2. ตั้งกติกาทีม เช่น ห้าม throw string, ต้องใช้ utility เดียวกัน, ต้อง log error เสมอ ฯลฯ
3. ใช้ utility function (อย่าง parseError/handleError) หรือพิจารณา lib เสริมเช่น neverthrow/Effect ถ้าตรงกับ use case
4. สำคัญที่สุดคืออย่าปล่อย error เงียบ จะใช้วิธีไหนก็ได้ ขอแค่มีแนวทางและใช้สม่ำเสมอ
.
การจัดการ error ไม่มีวิธีที่ “ดีที่สุด” แต่สิ่งที่แย่ที่สุดคือไม่จัดการอะไรเลย
Views: 5