JavaScript
Error Handling
การเลือก Error Type ให้เหมาะกับสถานการณ์
TypeError, RangeError, หรือ Error — เลือก type ยังไงให้เหมาะ และแยกประเภทใน catch ด้วย err.name
บทนำ — ทำไมการเลือก Error Type ถึงสำคัญ
จนถึงตอนนี้เราได้เรียนรู้ Error ทุกประเภทที่ JavaScript มี — SyntaxError, TypeError, ReferenceError, RangeError — เราเข้าใจว่าแต่ละตัวเกิดจากอะไร เกิดตอนไหน และมี `.name` กับ `.message` อย่างไร เราได้เรียนรู้ `throw` — วิธีโยน Error object ขึ้น Call Stack เพื่อหยุดโปรแกรมเมื่อเจอข้อผิดพลาด เราได้เรียนรู้ `try...catch...finally` — วิธีดักจับและจัดการ Error โดยไม่ให้โปรแกรมหยุด ตอนนี้ถึงเวลาของทักษะที่สำคัญที่สุดอีกหนึ่งอย่าง: **เมื่อเราเจอสถานการณ์ที่ต้อง `throw` — เราควรโยน Error ประเภทไหน?** คำถามนี้สำคัญเพราะ: 1. **ช่วยให้ debug เร็วขึ้น** — ถ้าเห็น `TypeError: price ต้องเป็น number` เรารู้ทันทีว่าปัญหาคือ type — เร็วกว่าการเห็นแค่ `Error: price ต้องเป็น number` ซึ่งต้องอ่าน message ถึงจะรู้สาเหตุ 2. **ช่วยให้ catch แยกประเภท Error ได้** — ด้วย `err.name === "TypeError"` เราจัดการ error แต่ละประเภทต่างกันได้ — TypeError อาจแค่แจ้งเตือนผู้ใช้, RangeError อาจต้อง log และหยุดระบบบางส่วน 3. **สื่อเจตนาให้คนอื่นเข้าใจ** — การเลือก `RangeError` บอกคนที่อ่านโค้ดว่า "ปัญหานี้เกี่ยวกับค่าที่อยู่นอกช่วง" — เป็นข้อมูลที่มีความหมายมากกว่า `Error` ธรรมดา บทเรียนนี้คือการ**รวมทุกอย่างที่เราเรียนรู้มา** — เราจะใช้ทั้ง Error Object, throw, และ try...catch — และโฟกัสที่**การตัดสินใจ**: เมื่อเจอสถานการณ์แบบนี้ ควรเลือก Error ประเภทไหนถึงจะดีที่สุด
การเลือก Error type ที่ถูกต้องทำให้ชื่อ error (.name) สื่อสาเหตุของปัญหาได้ตรงจุด — เปรียบเทียบ Error ทั่วไป vs TypeError vs RangeError ในสถานการณ์เดียวกัน
// ❌ ทุกอย่างเป็น Error หมด — .name ไม่ช่วยบอกสาเหตุ
function processOrder(quantity, price) {
if (typeof quantity !== "number") {
throw new Error("quantity ต้องเป็น number");
// ^ .name = "Error" — ไม่รู้ว่าเกี่ยวกับ type ถ้าดูแค่ .name
}
if (quantity < 1 || quantity > 100) {
throw new Error("quantity ต้องอยู่ระหว่าง 1 ถึง 100");
// ^ .name = "Error" — ไม่รู้ว่าเกี่ยวกับ range
}
if (price <= 0) {
throw new Error("price ต้องมากกว่า 0");
// ^ .name = "Error" — ดู .name อย่างเดียวไม่รู้ว่าเป็นเรื่องอะไร
}
}
// ✅ เลือก Error type ให้ตรงกับสาเหตุ — .name สื่อปัญหาได้ทันที
function processOrder(quantity, price) {
if (typeof quantity !== "number") {
throw new TypeError("quantity ต้องเป็น number");
// ^ .name = "TypeError" — เห็นปุ๊บรู้เลยว่า type ผิด
}
if (quantity < 1 || quantity > 100) {
throw new RangeError("quantity ต้องอยู่ระหว่าง 1 ถึง 100");
// ^ .name = "RangeError" — เห็นปุ๊บรู้เลยว่าค่าอยู่นอกช่วง
}
if (price <= 0) {
throw new Error("price ต้องมากกว่า 0");
// ^ .name = "Error" — ข้อผิดพลาดด้าน logic ทั่วไป
}
}- เรารู้จัก Error แต่ละประเภทแล้ว — ตอนนี้เราจะเรียนรู้**เมื่อไหร่ควรใช้แต่ละประเภท**
- การเลือก Error type ที่ถูกต้องช่วย 3 ด้าน: debug เร็ว, catch แยกประเภทได้, สื่อเจตนาชัดเจน
- `Error` อย่างเดียวใช้ได้ในทุกกรณี — แต่การเลือกชนิดที่เจาะจงกว่า (TypeError, RangeError) ทำให้ `.name` มีประโยชน์ในการ debug และใน catch
- บทเรียนนี้ไม่มีของใหม่ให้เรียน — เป็นการ**ประกอบความรู้ที่มี**เข้าด้วยกันเพื่อให้ตัดสินใจเก่งขึ้น
หลักการตัดสินใจเลือก Error Type
เวลาต้องตัดสินใจว่าจะ throw Error ประเภทไหน ให้ถามตัวเองด้วย **3 คำถาม** ตามลำดับนี้: **คำถามที่ 1: ปัญหาเกิดจาก type ของค่าหรือไม่?** - ใช่ → ใช้ **TypeError** - เช่น: ตรวจ `typeof` แล้วไม่ตรง, ตรวจ `instanceof` แล้วไม่ใช่, ค่าที่ควรเป็น function กลับไม่ใช่ function - ไม่ใช่ → ถามต่อ **คำถามที่ 2: ปัญหาเกิดจากค่าที่อยู่นอกช่วงหรือไม่?** - ใช่ → ใช้ **RangeError** - เช่น: จำนวนสินค้าน้อยกว่า 1, อายุเกิน 150, เปอร์เซ็นต์เกิน 100, ค่าติดลบทั้งที่ต้องการค่าบวก - ไม่ใช่ → ถามต่อ **คำถามที่ 3: เป็นข้อผิดพลาดที่ไม่ตรงกับ 2 ข้อข้างบนหรือไม่?** - ใช่ → ใช้ **Error** (พร้อม message ที่ดี) - เช่น: ข้อมูลไม่ครบ, กฎทางธุรกิจไม่ผ่าน, สถานะที่ยอมรับไม่ได้, การดำเนินการล้มเหลว **กฎทอง**: ถ้าไม่แน่ใจว่าใช้อะไร → ใช้ `Error` พร้อมข้อความที่ชัดเจน — การโยน `Error` ที่ message ดี ดีกว่าการโยน TypeError/RangeError ผิดที่
ฟังก์ชัน validateOrder สาธิตการใช้ 3 คำถาม: เช็ค type ก่อน → TypeError, เช็ค range → RangeError, ข้อผิดพลาดอื่น → Error
function validateOrder(order) {
// === คำถามที่ 1: ตรวจ type ===
if (typeof order !== "object" || order === null) {
throw new TypeError("order ต้องเป็น object");
}
if (typeof order.productName !== "string") {
throw new TypeError("productName ต้องเป็น string");
}
if (typeof order.quantity !== "number") {
throw new TypeError("quantity ต้องเป็น number");
}
// === คำถามที่ 2: ตรวจ range ===
if (order.quantity < 1) {
throw new RangeError("quantity ต้องมากกว่าหรือเท่ากับ 1 — แต่ได้รับ " + order.quantity);
}
if (order.quantity > 100) {
throw new RangeError("quantity ต้องไม่เกิน 100 — แต่ได้รับ " + order.quantity);
}
// === คำถามที่ 3: ข้อผิดพลาดด้าน logic ===
if (!order.productName || order.productName.trim() === "") {
throw new Error("productName ห้ามเป็นค่าว่าง");
}
if (order.productName.length > 200) {
throw new Error("productName ยาวเกินไป — ต้องไม่เกิน 200 ตัวอักษร");
}
console.log("✅ คำสั่งซื้อผ่านการตรวจสอบ:", order.productName, "x", order.quantity);
return true;
}
// ผ่านการตรวจสอบ
validateOrder({ productName: "หนังสือ JavaScript", quantity: 3 });
// output: ✅ คำสั่งซื้อผ่านการตรวจสอบ: หนังสือ JavaScript x 3
// ❌ TypeError — type ผิด
// validateOrder("ไม่ใช่ object");
// TypeError: order ต้องเป็น object
// ❌ RangeError — อยู่นอกช่วง
// validateOrder({ productName: "หนังสือ", quantity: 0 });
// RangeError: quantity ต้องมากกว่าหรือเท่ากับ 1 — แต่ได้รับ 0
// ❌ Error — ข้อผิดพลาดด้าน logic
// validateOrder({ productName: "", quantity: 5 });
// Error: productName ห้ามเป็นค่าว่าง| ขั้นตอน | คำถาม | ถ้าใช่ → ใช้ | ตัวอย่าง |
|---|---|---|---|
| 1 | ปัญหาเกี่ยวกับ type ของค่าหรือไม่? | `TypeError` | `typeof price !== "number"` → TypeError |
| 2 | ค่าอยู่นอกช่วงที่ยอมรับได้หรือไม่? | `RangeError` | `age < 0 || age > 150` → RangeError |
| 3 | เป็นข้อผิดพลาดด้าน logic หรือกฎธุรกิจ? | `Error` | ข้อมูลไม่ครบ, รูปแบบไม่ถูกต้อง, กฎธุรกิจไม่ผ่าน → Error |
- **ถามตัวเอง 3 คำถามตามลำดับ**: type? → TypeError / range? → RangeError / อื่น ๆ? → Error
- **ลำดับสำคัญ**: ตรวจ type ก่อน (พื้นฐานที่สุด) → ตรวจ range → ตรวจ logic (เฉพาะเจาะจงที่สุด)
- **กฎทอง**: ถ้าไม่แน่ใจ → `Error` พร้อม message ที่ดี — ดีกว่าโยน TypeError/RangeError ผิดที่
- **Error message ที่ดี** = บอกว่าอะไรผิด + ค่าที่ได้รับคืออะไร + ควรแก้อย่างไร (ถ้าบอกได้)
Error — เมื่อไหร่ควรใช้ Error ทั่วไป
`Error` เป็น Error type พื้นฐานที่สุด — และเป็น type ที่เราใช้**บ่อยที่สุด**เวลา `throw` เอง **ใช้ Error เมื่อ**: - ข้อผิดพลาด**ไม่เกี่ยวกับ type** (ไม่ใช่ TypeError) และ**ไม่เกี่ยวกับ range** (ไม่ใช่ RangeError) - เป็นข้อผิดพลาดด้าน **logic**, **กฎธุรกิจ**, หรือ **เงื่อนไขของโปรแกรม** - ข้อมูลไม่ครบ, รูปแบบข้อมูลไม่ถูกต้อง (ที่ไม่เกี่ยวกับ type), การดำเนินการล้มเหลว, สถานะที่ไม่คาดคิด **ข้อดีของ Error**: - ใช้ได้กับทุกสถานการณ์ — เป็น "default" choice ที่ปลอดภัย - ไม่ต้องคิดมาก — ถ้าไม่แน่ใจว่า TypeError หรือ RangeError → ใช้ Error แล้วใส่ message ดี ๆ **ข้อเสียของ Error**: - `.name` = `"Error"` — ไม่บอกเบาะแสว่าเป็น error ประเภทไหน ต้องอ่าน `.message` อย่างเดียว - ใน catch — `err.name === "Error"` จะดักจับ error ทุกประเภทที่ `.name` เป็น `"Error"` — ไม่สามารถแยกย่อยได้ **กุญแจสำคัญของ Error คือ `.message`**: เพราะ `.name` = `"Error"` เหมือนกันหมด — ความแตกต่างทั้งหมดอยู่ที่ `.message` — การเขียน message ที่ดีจึงสำคัญมากเป็นพิเศษสำหรับ `Error`
สำหรับ Error ทั่วไป message คือทุกสิ่ง — message ที่ดีบอกว่าอะไรผิด อะไรคือค่าที่ได้รับ และควรแก้อย่างไร
// ❌ message ที่ไม่เป็นประโยชน์ — เห็นแล้วไม่รู้ว่าอะไรผิด
throw new Error("ผิดพลาด");
throw new Error("error");
throw new Error("ข้อมูลไม่ถูกต้อง");
throw new Error("ไม่พบข้อมูล");
// ^ message พวกนี้บอกว่ามี error — แต่ไม่บอกว่าอะไรผิด หรือควรแก้ยังไง
// เวลาเจอ error จริงต้องเสียเวลาไล่หาเอง
// ✅ message ที่ดี — บอกว่าอะไรผิด + ค่าที่ได้รับ + ควรแก้อย่างไร
throw new Error("ไม่พบข้อมูลผู้ใช้ ID 12345 — อาจถูกลบไปแล้ว");
throw new Error("ยอดเงินคงเหลือไม่พอ — มี 500 บาท แต่ต้องการถอน 1000 บาท");
throw new Error("คำสั่งซื้อต้องมีรายการสินค้าอย่างน้อย 1 รายการ");
throw new Error("ไม่สามารถเชื่อมต่อฐานข้อมูลได้ — ตรวจสอบว่า server ทำงานอยู่หรือไม่");
// 💡 สูตร message ที่ดี:
// "อะไรผิด" + "ค่าที่ได้รับคืออะไร (ถ้ามี)" + "ควรแก้อย่างไร (ถ้าบอกได้)"
// เช่น: "ชื่อผู้ใช้ห้ามว่างเปล่า" + " — แต่ได้รับ """ + " — กรุณากรอกชื่อผู้ใช้"
// = "ชื่อผู้ใช้ห้ามว่างเปล่า — แต่ได้รับ "" — กรุณากรอกชื่อผู้ใช้"Error ใช้กับข้อผิดพลาดที่ไม่เกี่ยวกับ type หรือ range — กฎธุรกิจ, ข้อมูลไม่ครบ, การดำเนินการล้มเหลว, หรือสถานะที่ไม่คาดคิด
// ✅ ข้อมูลไม่ครบ — Error
function createUser(name, email) {
if (!name || name.trim() === "") {
throw new Error("name ห้ามเป็นค่าว่าง");
}
if (!email || email.trim() === "") {
throw new Error("email ห้ามเป็นค่าว่าง");
}
console.log("สร้างผู้ใช้:", name);
}
// ✅ กฎธุรกิจไม่ผ่าน — Error
function withdrawMoney(balance, amount) {
if (amount <= 0) {
throw new Error("จำนวนเงินที่ถอนต้องมากกว่า 0 — แต่ได้รับ " + amount);
}
if (amount > balance) {
throw new Error("ยอดเงินไม่พอ — มียอดคงเหลือ " + balance + " บาท แต่ต้องการถอน " + amount + " บาท");
}
return balance - amount;
}
console.log(withdrawMoney(1000, 300)); // 700
// ✅ สถานะที่ไม่ถูกต้อง — Error
let isLoggedIn = false;
function getProfile() {
if (!isLoggedIn) {
throw new Error("ยังไม่ได้เข้าสู่ระบบ — กรุณา login ก่อนดูโปรไฟล์");
}
return { name: "สมชาย", role: "member" };
}
// getProfile();
// Error: ยังไม่ได้เข้าสู่ระบบ — กรุณา login ก่อนดูโปรไฟล์- **`Error`** ใช้สำหรับข้อผิดพลาดด้าน logic, กฎธุรกิจ, ข้อมูลไม่ครบ, หรือสถานะที่ยอมรับไม่ได้
- **Error คือ default choice**: ถ้าไม่แน่ใจว่า TypeError หรือ RangeError → ใช้ Error (ดีกว่าโยนผิดประเภท)
- **message คือหัวใจของ Error**: เพราะ `.name` = `"Error"` เหมือนกันหมด — message ต้องบอกว่าอะไรผิด, ค่าที่ได้รับ, และควรแก้อย่างไร
- **อย่าใช้ Error เมื่อเข้าเกณฑ์ TypeError หรือ RangeError**: ถ้าเป็นเรื่อง type → TypeError, ถ้าเป็นเรื่อง range → RangeError — ใช้ Error เฉพาะกรณีที่ไม่ตรงกับ 2 ประเภทนั้น
TypeError — เมื่อไหร่ควรใช้ TypeError
**TypeError** ใช้เมื่อค่าที่ได้รับมี **type ไม่ตรงตามที่ function คาดหวัง** เราได้เรียนรู้ TypeError อย่างละเอียดในบทก่อน — รู้ว่ามันเกิดตอน runtime, มีสาเหตุหลักอะไรบ้าง, และป้องกันได้ด้วย `typeof` ตอนนี้โฟกัสที่คำถามเดียว: **เมื่อไหร่ที่เราในฐานะคนเขียนโค้ดควร `throw new TypeError(...)` ด้วยตัวเอง?** **ใช้ TypeError เมื่อ**: - ตรวจ `typeof` แล้ว type ไม่ตรง — เช่น function ต้องการ number แต่ได้รับ string - ตรวจ `instanceof` แล้วไม่ใช่ instance ที่คาดหวัง — เช่น ต้องการ `Date` object แต่ได้รับ object ธรรมดา - ตรวจสอบว่าเป็น array หรือไม่ด้วย `Array.isArray()` - ค่าที่รับมาเป็น `null` หรือ `undefined` ทั้งที่ function ต้องการค่าที่มีอยู่จริง (แต่ระวัง — การอ่าน property ของ null ก็เกิด TypeError อยู่แล้ว — การ throw เองทำให้ message ชัดเจนกว่า) **ไม่ควรใช้ TypeError เมื่อ**: - ค่า type ถูกต้อง แต่อยู่นอกช่วง — อันนั้นคือ RangeError - ค่า type ถูกต้อง อยู่ในช่วงที่รับได้ แตผิดกฎธุรกิจ — อันนั้นคือ Error - เป็น SyntaxError หรือ ReferenceError — TypeError ไม่ใช่ตัวแทนของ error ทุกประเภท
ใช้ TypeError เมื่อ typeof ไม่ตรง — ทำให้ caller รู้ทันทีว่า .name บ่งบอกว่าเป็นปัญหา type พร้อม message ที่บอก type ที่คาดหวังและ type ที่ได้รับจริง
// ✅ TypeError — ตรวจ type ของ argument
function repeatText(text, times) {
if (typeof text !== "string") {
throw new TypeError("text ต้องเป็น string — แต่ได้รับ " + typeof text);
}
if (typeof times !== "number") {
throw new TypeError("times ต้องเป็น number — แต่ได้รับ " + typeof times);
}
return text.repeat(times);
}
console.log(repeatText("Hi", 3)); // "HiHiHi"
// ❌ TypeError — type ผิด
// repeatText(123, 3);
// TypeError: text ต้องเป็น string — แต่ได้รับ number
// ✅ TypeError — ตรวจว่าเป็นฟังก์ชันก่อนเรียก
function safeExecute(fn) {
if (typeof fn !== "function") {
throw new TypeError("fn ต้องเป็น function — แต่ได้รับ " + typeof fn);
}
fn();
}
safeExecute(() => console.log("ทำงาน!")); // "ทำงาน!"
// safeExecute("ไม่ใช่ฟังก์ชัน");
// TypeError: fn ต้องเป็น function — แต่ได้รับ stringtype ผิด → TypeError / ข้อมูลไม่ครบ → Error — แยกให้ออก อย่าใช้ TypeError แทน Error ในเมื่อปัญหาไม่เกี่ยวกับ type
// ✅ type ผิด — TypeError (ถูกต้อง)
function setAge(age) {
if (typeof age !== "number") {
throw new TypeError("age ต้องเป็น number — แต่ได้รับ " + typeof age);
// ^ ปัญหาคือ type ไม่ตรง → TypeError คือตัวเลือกที่ถูกต้อง
}
// ...
}
// ❌ ใช้ TypeError กับสิ่งที่ไม่เกี่ยวกับ type — ผิด
function setAge(age) {
if (typeof age !== "number") {
throw new TypeError("age ต้องเป็น number");
}
if (age < 0) {
throw new TypeError("age ต้องมากกว่า 0"); // ❌ ผิด! — นี่คือ RangeError ไม่ใช่ TypeError
}
}
// ✅ แก้ไข — แยก type error กับ range error
function setAge(age) {
if (typeof age !== "number") {
throw new TypeError("age ต้องเป็น number — แต่ได้รับ " + typeof age);
}
if (age < 0) {
throw new RangeError("age ต้องมากกว่าหรือเท่ากับ 0 — แต่ได้รับ " + age);
// ^ ปัญหาคือค่าอยู่นอกช่วง → RangeError คือตัวเลือกที่ถูกต้อง
}
if (age > 150) {
throw new RangeError("age ต้องไม่เกิน 150 — แต่ได้รับ " + age);
}
console.log("อายุ:", age);
}
setAge(25); // "อายุ: 25"
// ✅ ข้อมูลไม่ครบ — ไม่เกี่ยวกับ type → Error
function register(name, age) {
if (typeof name !== "string") {
throw new TypeError("name ต้องเป็น string"); // type → TypeError
}
if (typeof age !== "number") {
throw new TypeError("age ต้องเป็น number"); // type → TypeError
}
if (name.trim() === "") {
throw new Error("name ห้ามเป็นค่าว่าง"); // ข้อมูลไม่ครบ → Error
// ^ แม้ name จะเป็น string (type ถูกต้อง) — แต่เป็นค่าว่าง
// นี่ไม่ใช่ปัญหา type — เป็นปัญหา logic → Error
}
console.log("ลงทะเบียน:", name, "อายุ:", age);
}
register("สมชาย", 30); // "ลงทะเบียน: สมชาย อายุ: 30"- **TypeError** ใช้เมื่อ type ของค่าไม่ตรงตามที่คาดหวัง — เช็คด้วย `typeof`, `instanceof`, หรือ `Array.isArray()`
- **message บอก type ที่คาดหวัง และ type ที่ได้รับจริง** — เช่น `"age ต้องเป็น number — แต่ได้รับ string"`
- **อย่าใช้ TypeError เมื่อไม่เกี่ยวกับ type**: ค่าอยู่นอกช่วง → RangeError, ข้อมูลไม่ครบหรือกฎธุรกิจไม่ผ่าน → Error
- **TypeError ที่ดี** = `.name` บอกว่า type ผิด + `.message` บอกว่า type อะไรที่คาดหวังและได้รับอะไร
RangeError — เมื่อไหร่ควรใช้ RangeError
**RangeError** ใช้เมื่อค่ามี type **ถูกต้องแล้ว** — แต่อยู่**นอกช่วงที่ยอมรับได้** เราได้เรียนรู้ RangeError อย่างละเอียดในบทก่อน — รู้ว่ามันเกิดได้จาก `toFixed()` digits เกิน 100, `new Array(-1)`, `repeat(-1)`, หรือ recursion ที่ call stack ล้น ตอนนี้โฟกัสที่คำถามเดียว: **เมื่อไหร่ที่เราในฐานะคนเขียนโค้ดควร `throw new RangeError(...)` ด้วยตัวเอง?** **ใช้ RangeError เมื่อ**: - ตัวเลขอยู่นอกช่วงที่ยอมรับได้ — เช่น จำนวนสินค้าน้อยกว่า 1, อายุเกิน 150, เปอร์เซ็นต์เกิน 100 - ความยาวหรือขนาดเกินขีดจำกัด — เช่น ชื่อผู้ใช้เกิน 50 ตัวอักษร, จำนวนรายการใน array เกิน 1000 - การตรวจสอบ range **หลังจาก**ตรวจสอบ type ผ่านแล้ว — type ต้องถูกต้องก่อน ถึงจะตรวจ range **ไม่ควรใช้ RangeError เมื่อ**: - type ผิดตั้งแต่แรก — อันนั้นคือ TypeError - ข้อผิดพลาดไม่เกี่ยวกับ range — เช่น ข้อมูลไม่ครบ, กฎธุรกิจไม่ผ่าน → Error - ต้องการเลียนแบบ RangeError ที่ JavaScript สร้างเอง — เช่น `Maximum call stack size exceeded` — เราทำซ้ำไม่ได้ (และไม่ควร)
RangeError ใช้เมื่อค่ามี type ถูกต้องแล้ว แต่อยู่นอกช่วงที่ยอมรับได้ — เช่น จำนวนติดลบเมื่อต้องการบวก, เปอร์เซ็นต์เกิน 100
// ✅ RangeError — ปริมาณอยู่นอกช่วง
function orderItem(quantity) {
if (typeof quantity !== "number") {
throw new TypeError("quantity ต้องเป็น number — แต่ได้รับ " + typeof quantity);
}
if (quantity < 1) {
throw new RangeError("quantity ต้องมากกว่าหรือเท่ากับ 1 — แต่ได้รับ " + quantity);
}
if (quantity > 1000) {
throw new RangeError("quantity ต้องไม่เกิน 1000 — แต่ได้รับ " + quantity);
}
console.log("สั่งสินค้าจำนวน:", quantity, "ชิ้น");
}
orderItem(5); // "สั่งสินค้าจำนวน: 5 ชิ้น"
orderItem(1); // "สั่งสินค้าจำนวน: 1 ชิ้น"
orderItem(1000); // "สั่งสินค้าจำนวน: 1000 ชิ้น"
// ❌ RangeError — อยู่นอกช่วง
// orderItem(0);
// RangeError: quantity ต้องมากกว่าหรือเท่ากับ 1 — แต่ได้รับ 0
// ✅ RangeError — เปอร์เซ็นต์เกินช่วง
function applyDiscount(percent) {
if (typeof percent !== "number") {
throw new TypeError("percent ต้องเป็น number");
}
if (percent < 0 || percent > 100) {
throw new RangeError("percent ต้องอยู่ระหว่าง 0 ถึง 100 — แต่ได้รับ " + percent);
}
console.log("ส่วนลด:", percent + "%");
}
applyDiscount(20); // "ส่วนลด: 20%"
applyDiscount(0); // "ส่วนลด: 0%"
applyDiscount(100); // "ส่วนลด: 100%"
// ❌ RangeError
// applyDiscount(150);
// RangeError: percent ต้องอยู่ระหว่าง 0 ถึง 100 — แต่ได้รับ 150ความยาว string เกินกำหนด, จำนวนรายการใน array เกินลิมิต — ใช้ RangeError เมื่อเป็นเรื่องของ "มากเกินไป" หรือ "น้อยเกินไป"
// ✅ RangeError — ชื่อผู้ใช้ยาวเกินกำหนด
function setUsername(name) {
if (typeof name !== "string") {
throw new TypeError("name ต้องเป็น string");
}
if (name.length === 0) {
throw new Error("name ห้ามเป็นค่าว่าง"); // ข้อมูลไม่ครบ → Error
}
if (name.length > 30) {
throw new RangeError("ชื่อผู้ใช้ต้องไม่เกิน 30 ตัวอักษร — ตอนนี้ " + name.length + " ตัวอักษร");
// ^ ความยาวเกิน → RangeError — เพราะเป็นเรื่องของ "เกินขอบเขตที่กำหนด"
}
console.log("ตั้งชื่อผู้ใช้:", name);
}
setUsername("somchai"); // "ตั้งชื่อผู้ใช้: somchai"
// ❌ RangeError — ยาวเกิน
// setUsername("ชื่อนี้ยาวมากเกินกว่าสามสิบตัวอักษรจึงไม่สามารถใช้ได้");
// RangeError: ชื่อผู้ใช้ต้องไม่เกิน 30 ตัวอักษร — ตอนนี้ 42 ตัวอักษร
// ✅ RangeError — จำนวนรายการใน array เกินลิมิต
function addToList(list, item) {
if (!Array.isArray(list)) {
throw new TypeError("list ต้องเป็น array");
}
if (list.length >= 100) {
throw new RangeError("รายการเต็มแล้ว — รับได้สูงสุด 100 รายการ");
}
list.push(item);
console.log("เพิ่มรายการ — ตอนนี้มี", list.length, "รายการ");
}
let todoList = [];
addToList(todoList, "ซื้อข้าว"); // "เพิ่มรายการ — ตอนนี้มี 1 รายการ"- **RangeError** ใช้เมื่อค่ามี type ถูกต้อง แต่อยู่นอกช่วง — ตรวจ type ก่อน แล้วค่อยตรวจ range
- **ใช้กับ**: ตัวเลขเกินช่วง (จำนวน, เปอร์เซ็นต์, ดัชนี), ความยาวหรือขนาดเกินกำหนด (string ยาวไป, array เต็ม), ข้อจำกัดด้านปริมาณ
- **message บอกช่วงที่ยอมรับได้ และค่าที่ได้รับ** — เช่น `"age ต้องอยู่ระหว่าง 0 ถึง 150 — แต่ได้รับ -5"`
- **อย่าใช้ RangeError เมื่อ**: type ผิด → TypeError, ข้อมูลไม่ครบหรือกฎธุรกิจไม่ผ่าน → Error, หรือปัญหาที่ JavaScript engine เท่านั้นที่สร้าง RangeError นั้น (เช่น stack overflow)
Error Type ที่ไม่ควร throw เอง
JavaScript มี Error ประเภทอื่น ๆ นอกจาก Error, TypeError, และ RangeError — แต่**ไม่ใช่ทุกประเภทที่เหมาะกับการ `throw` เอง** Error บางประเภทมีหน้าที่เฉพาะใน JavaScript engine — การ throw มันเองจะทำให้เกิดความสับสน เพราะคนที่เห็น error จะคิดว่า JavaScript engine เป็นคนสร้าง error นั้น ทั้งที่จริง ๆ เราเป็นคน throw หลักการ: **เรา throw เฉพาะ Error, TypeError, และ RangeError** — error ประเภทอื่นส่วนใหญ่ JavaScript engine เป็นคนสร้างให้เรา เราไม่ควรแทรกแซง
| Error Type | ใครเป็นคนสร้าง | ควร throw เองหรือไม่ | ถ้าอยาก throw — ใช้อะไรแทน |
|---|---|---|---|
| `Error` | เรา (programmer) | ✅ **ควร** — ใช้บ่อยที่สุด | — |
| `TypeError` | เรา (programmer) หรือ JavaScript engine | ✅ **ควร** — เมื่อตรวจ type แล้วไม่ตรง | — |
| `RangeError` | เรา (programmer) หรือ JavaScript engine | ✅ **ควร** — เมื่อค่าอยู่นอกช่วง | — |
| `SyntaxError` | JavaScript engine เท่านั้น — เกิดตอน parse | ❌ **ไม่ควร** — SyntaxError เกิดตอน parse ก่อนโค้ดรัน | ใช้ `Error` พร้อม message ที่บอกว่าข้อมูลไม่ถูก format |
| `ReferenceError` | JavaScript engine เท่านั้น — เมื่อตัวแปรไม่มีใน scope | ❌ **ไม่ควร** — เป็นกลไกภายในของ JavaScript | ใช้ `Error` หรือ `TypeError` — บอกว่าตัวแปรไม่มีค่าหรือไม่ได้กำหนด |
| `EvalError` | JavaScript engine (สมัยก่อน) — ปัจจุบันไม่ใช้แล้ว | ❌ **ไม่ควร** — เลิกใช้แล้วใน JavaScript สมัยใหม่ | ใช้ `Error` เสมอ |
| `URIError` | JavaScript engine — เมื่อ `encodeURI()` หรือ `decodeURI()` ได้รับ URI ที่ผิดรูปแบบ | ❌ **ไม่ควร** — เฉพาะเจาะจงมาก ไม่ควร throw เอง | ใช้ `Error` หรือ `TypeError` |
การ throw SyntaxError เองทำให้เกิดความสับสน — SyntaxError ควรเกิดตอน parse โดย JS engine เท่านั้น
// ❌ อย่า throw SyntaxError เอง!
function parseJson(jsonString) {
try {
return JSON.parse(jsonString);
} catch (err) {
// ❌ ผิด — อย่า throw SyntaxError เอง
throw new SyntaxError("JSON ไม่ถูกต้อง: " + err.message);
// ^ ปัญหา: คนที่เห็น error นี้จะคิดว่าเกิด SyntaxError ตอน parse
// แต่จริง ๆ เราเป็นคน throw — ทำให้ debug สับสน
}
}
// ✅ ใช้ Error แทน — พร้อม message ที่เป็นประโยชน์
function parseJson(jsonString) {
try {
return JSON.parse(jsonString);
} catch (err) {
// ✅ ถูกต้อง — ใช้ Error พร้อมข้อมูลที่เป็นประโยชน์
throw new Error("ข้อมูล JSON ไม่ถูกต้อง — " + err.message);
// ^ .name = "Error" — ชัดเจนว่าเราเป็นคน throw
// .message มีทั้งสาเหตุและรายละเอียด
}
}
// ========================================
// ❌ อย่า throw ReferenceError เอง!
function getUser(userId) {
if (userId === undefined) {
// ❌ ผิด — อย่า throw ReferenceError
throw new ReferenceError("userId is not defined");
// ^ ปัญหา: ReferenceError ควรเกิดเมื่อ JavaScript engine หาตัวแปรไม่เจอ
// การ throw เองทำให้ debug สับสน — คิดว่าตัวแปรไม่มีอยู่จริง
}
}
// ✅ ใช้ Error หรือ TypeError แทน
function getUser(userId) {
if (userId === undefined) {
// ✅ ถูกต้อง — ใช้ Error
throw new Error("userId is required — ไม่ได้รับค่า userId");
}
return { id: userId, name: "สมชาย" };
}
// ✅ หรือถ้าต้องการระบุว่าเป็นปัญหาเกี่ยวกับค่าที่ไม่ถูกส่งมา
function getUser(userId) {
if (userId === undefined) {
throw new TypeError("userId is required — expected string or number, but received undefined");
// ^ TypeError ก็ใช้ได้ — เพราะ undefined เป็น type หนึ่งที่เราไม่คาดหวัง
}
return { id: userId, name: "สมชาย" };
}**สรุปกฎง่าย ๆ**: - **throw เองได้**: `Error`, `TypeError`, `RangeError` — 3 ตัวนี้ครอบคลุมทุกสถานการณ์ที่เราต้อง throw ในโค้ดปกติ - **ไม่ควร throw เอง**: `SyntaxError`, `ReferenceError` — ปล่อยให้ JavaScript engine จัดการ - **ไม่มีเหตุผลที่จะ throw**: `EvalError` — เลิกใช้แล้ว, `URIError` — เฉพาะทางเกินไป ถ้าจำไม่ได้ว่าตัวไหน throw ได้ → ใช้ `Error` — ปลอดภัยเสมอ
- **throw เองได้ 3 ตัว**: `Error`, `TypeError`, `RangeError`
- **ห้าม throw เอง**: `SyntaxError` (เกิดตอน parse), `ReferenceError` (เกิดเมื่อตัวแปรไม่มีใน scope) — เป็นกลไกภายในของ JavaScript
- **EvalError** และ **URIError** — ไม่มีเหตุผลที่ต้อง throw เองในโค้ดปกติ
- **ถ้าไม่แน่ใจ → `Error`**: การโยน `Error` ดีกว่าการโยน SyntaxError หรือ ReferenceError ผิดที่
- **หลักการ**: เรา throw error ที่สื่อสาเหตุของปัญหา — ไม่ใช่ throw เพื่อเลียนแบบ JavaScript engine
การเลือก Error Type ส่งผลต่อ catch อย่างไร
นี่คือ **เหตุผลที่สำคัญที่สุด** ที่เราต้องเลือก Error type ให้ดี — เพราะการเลือกที่ถูกต้องทำให้เรา**แยกประเภท error ใน catch ได้** และจัดการแต่ละประเภทแตกต่างกันได้อย่างเหมาะสม ลองนึกภาพว่าเราใช้ `Error` อย่างเดียวทั้งหมด — เวลาเจอ error ใน catch เราต้องอ่าน `.message` เพื่อเดาว่าเป็น error ประเภทไหน — ซึ่งเสี่ยงต่อการเข้าใจผิดและจัดการผิดวิธี แต่ถ้าเราเลือก Error type อย่างเหมาะสม: - `TypeError` — เรารู้ทันทีว่าผู้ใช้ส่งข้อมูล type ผิด → แสดงข้อความให้ผู้ใช้แก้ไข - `RangeError` — เรารู้ทันทีว่าค่าที่ส่งมาเกินช่วง → แสดงข้อความบอกช่วงที่ถูกต้อง - `Error` — เรา log ไว้ debug เพราะเป็นข้อผิดพลาดที่อาจเกิดจากบัคหรือสถานะที่ไม่คาดคิด การแยกประเภท error ใน catch ทำได้ 2 วิธี: 1. **`err.name`** — เช็ค string: `err.name === "TypeError"` 2. **`err instanceof TypeError`** — เช็คด้วย instanceof (ต้องใช้ `new TypeError(...)` ตอน throw) ทั้ง 2 วิธีให้ผลลัพธ์เหมือนกัน — `err.name` มักอ่านง่ายกว่า ส่วน `instanceof` แข็งแรงกว่าเมื่อมี inheritance
processPayment ตรวจสอบข้อมูลหลายด้าน — แต่ละด้านใช้ Error type ต่างกันตามสาเหตุ ทำให้ catch จัดการได้ตรงจุด
function processPayment(payment) {
// ตรวจ type → TypeError
if (typeof payment !== "object" || payment === null) {
throw new TypeError("payment ต้องเป็น object");
}
if (typeof payment.amount !== "number") {
throw new TypeError("payment.amount ต้องเป็น number");
}
if (typeof payment.method !== "string") {
throw new TypeError("payment.method ต้องเป็น string");
}
// ตรวจ range → RangeError
if (payment.amount <= 0) {
throw new RangeError("จำนวนเงินต้องมากกว่า 0 — แต่ได้รับ " + payment.amount);
}
if (payment.amount > 100000) {
throw new RangeError("จำนวนเงินต้องไม่เกิน 100,000 — แต่ได้รับ " + payment.amount);
}
// ตรวจ logic และกฎธุรกิจ → Error
let validMethods = ["credit-card", "bank-transfer", "e-wallet"];
if (!validMethods.includes(payment.method)) {
throw new Error(
"วิธีการชำระเงินไม่ถูกต้อง — ต้องเป็น " + validMethods.join(", ") +
" — แต่ได้รับ "" + payment.method + """
);
}
console.log("💳 ชำระเงิน " + payment.amount + " บาท ผ่าน " + payment.method);
return { status: "success", amount: payment.amount };
}ใช้ err.name แยกประเภท error — TypeError → แจ้งผู้ใช้ให้ตรวจสอบข้อมูล, RangeError → แจ้งช่วงที่ถูกต้อง, Error → log แล้วแจ้งทั่วไป
// ฟังก์ชันหลัก — เรียก processPayment และจัดการ error แต่ละประเภท
function handlePayment(paymentData) {
try {
let result = processPayment(paymentData);
console.log("✅ การชำระเงินสำเร็จ:", result);
return result;
} catch (err) {
// แยกการจัดการตามประเภท error
if (err.name === "TypeError") {
// ปัญหาเกี่ยวกับ type — ผู้ใช้ส่งข้อมูลผิด format
console.log("❌ รูปแบบข้อมูลไม่ถูกต้อง:", err.message);
console.log(" → แสดงข้อความให้ผู้ใช้ตรวจสอบข้อมูลที่กรอก");
return { status: "error", reason: "invalid_format", detail: err.message };
} else if (err.name === "RangeError") {
// ปัญหาเกี่ยวกับ range — ผู้ใช้ส่งจำนวนเงินเกินช่วง
console.log("❌ จำนวนเงินอยู่นอกช่วงที่รับได้:", err.message);
console.log(" → แสดงข้อความบอกช่วงที่ถูกต้องให้ผู้ใช้");
return { status: "error", reason: "out_of_range", detail: err.message };
} else {
// Error อื่น ๆ — ข้อผิดพลาดที่ไม่คาดคิด
console.log("❌ เกิดข้อผิดพลาด:", err.message);
console.log(" → log ไว้ debug แล้วแจ้งผู้ใช้แบบทั่วไป");
return { status: "error", reason: "unknown", detail: err.message };
}
}
}
// ทดสอบ — ข้อมูลถูกต้อง
console.log(handlePayment({ amount: 500, method: "credit-card" }));
// output:
// 💳 ชำระเงิน 500 บาท ผ่าน credit-card
// ✅ การชำระเงินสำเร็จ: { status: "success", amount: 500 }
// { status: "success", amount: 500 }
console.log("==========");
// ทดสอบ — TypeError: amount ไม่ใช่ number
console.log(handlePayment({ amount: "ห้าร้อย", method: "credit-card" }));
// output:
// ❌ รูปแบบข้อมูลไม่ถูกต้อง: payment.amount ต้องเป็น number
// → แสดงข้อความให้ผู้ใช้ตรวจสอบข้อมูลที่กรอก
// { status: "error", reason: "invalid_format", detail: "payment.amount ต้องเป็น number" }
console.log("==========");
// ทดสอบ — RangeError: จำนวนเงินเกิน 100,000
console.log(handlePayment({ amount: 500000, method: "bank-transfer" }));
// output:
// ❌ จำนวนเงินอยู่นอกช่วงที่รับได้: จำนวนเงินต้องไม่เกิน 100,000 — แต่ได้รับ 500000
// → แสดงข้อความบอกช่วงที่ถูกต้องให้ผู้ใช้
// { status: "error", reason: "out_of_range", detail: "จำนวนเงินต้องไม่เกิน 100,000 — แต่ได้รับ 500000" }
console.log("==========");
// ทดสอบ — Error: วิธีการชำระเงินไม่ถูกต้อง
console.log(handlePayment({ amount: 500, method: "cash" }));
// output:
// ❌ เกิดข้อผิดพลาด: วิธีการชำระเงินไม่ถูกต้อง — ต้องเป็น credit-card, bank-transfer, e-wallet — แต่ได้รับ "cash"
// → log ไว้ debug แล้วแจ้งผู้ใช้แบบทั่วไป
// { status: "error", reason: "unknown", detail: "วิธีการชำระเงินไม่ถูกต้อง — ต้องเป็น credit-card, bank-transfer, e-wallet — แต่ได้รับ "cash"" }ถ้าทุกอย่างเป็น Error หมด — err.name จะเป็น "Error" เหมือนกันหมด — เราแยกไม่ได้ว่าเป็นปัญหา type, range, หรือ logic — ต้องอ่าน message อย่างเดียว
// ❌ ถ้าใช้ Error อย่างเดียว ทุกอย่าง — catch จัดการแยกประเภทไม่ได้
function processPaymentBad(payment) {
if (typeof payment.amount !== "number") {
throw new Error("amount ต้องเป็น number"); // .name = "Error"
}
if (payment.amount <= 0) {
throw new Error("amount ต้องมากกว่า 0"); // .name = "Error"
}
if (!["credit-card", "bank-transfer"].includes(payment.method)) {
throw new Error("method ไม่ถูกต้อง"); // .name = "Error"
}
}
// ใน catch — แยกไม่ได้ว่าเป็นปัญหาอะไร
try {
processPaymentBad({ amount: -100, method: "cash" });
} catch (err) {
// err.name === "Error" — เหมือนกันหมดทั้ง 3 กรณี!
// ต้องพึ่ง err.message เพื่อเดาว่าปัญหาคืออะไร:
// - "amount ต้องเป็น number" — น่าจะเกี่ยวกับ type
// - "amount ต้องมากกว่า 0" — น่าจะเกี่ยวกับ range
// - "method ไม่ถูกต้อง" — น่าจะเกี่ยวกับ logic
//
// แต่การเช็ค err.message เป็น string เปราะบาง —
// ถ้าเราเปลี่ยน message ต้องเปลี่ยน catch ด้วย ❌
console.log(err.name, "-", err.message);
}
// ========================================
// ✅ ใช้ Error type ที่ถูกต้อง — catch แยกได้ด้วย err.name
function processPaymentGood(payment) {
if (typeof payment.amount !== "number") {
throw new TypeError("amount ต้องเป็น number"); // .name = "TypeError"
}
if (payment.amount <= 0) {
throw new RangeError("amount ต้องมากกว่า 0"); // .name = "RangeError"
}
if (!["credit-card", "bank-transfer"].includes(payment.method)) {
throw new Error("method ไม่ถูกต้อง"); // .name = "Error"
}
}
try {
processPaymentGood({ amount: -100, method: "cash" });
} catch (err) {
// ✅ แยกประเภทได้ทันทีด้วย err.name
if (err.name === "TypeError") {
console.log("→ จัดการปัญหา type: แจ้งผู้ใช้ให้ตรวจสอบ format");
} else if (err.name === "RangeError") {
console.log("→ จัดการปัญหา range: แจ้งผู้ใช้ให้ตรวจสอบจำนวนเงิน");
} else {
console.log("→ จัดการปัญหาอื่น: log แล้วแจ้งผู้ใช้ทั่วไป");
}
// ^ ต่อให้เราเปลี่ยน message — catch ยังทำงานถูกเพราะอิงกับ err.name
}
// output:
// → จัดการปัญหา range: แจ้งผู้ใช้ให้ตรวจสอบจำนวนเงิน- **การเลือก Error type ที่ถูกต้องทำให้ catch แยกประเภท error ได้** — ด้วย `err.name` หรือ `err instanceof`
- **ถ้าใช้ Error อย่างเดียวทั้งหมด**: err.name = `"Error"` เหมือนกัน — แยกประเภทไม่ได้ ต้องอ่าน message ซึ่งเปราะบาง
- **รูปแบบที่แนะนำ**: `err.name === "TypeError"` → จัดการแบบหนึ่ง, `err.name === "RangeError"` → จัดการอีกแบบ, else → จัดการแบบ general
- **ประโยชน์**: เปลี่ยน message ได้โดยไม่กระทบ catch — เพราะ catch อิงกับ `.name` ไม่ใช่ `.message`
- **`err instanceof TypeError`** ก็ใช้ได้ — ให้ผลเหมือน `err.name === "TypeError"` — เลือกใช้ตามความถนัด
- **นี่คือเหตุผลที่เราควรเลือก Error type ให้ดี** — ไม่ใช่แค่เพื่อความสวยงามของโค้ด — แต่เพื่อให้ระบบจัดการ error ของเราทำงานได้อย่างมีประสิทธิภาพ
สรุป — ตารางตัดสินใจเลือก Error Type
| สถานการณ์ | Error Type ที่ควรใช้ | ตัวอย่าง message |
|---|---|---|
| ตรวจ `typeof` แล้ว type ไม่ตรง | `TypeError` | `"price ต้องเป็น number — แต่ได้รับ string"` |
| ตรวจ `instanceof` แล้วไม่ใช่ instance ที่คาดหวัง | `TypeError` | `"config ต้องเป็น Date object"` |
| ตรวจ `Array.isArray()` แล้วไม่ใช่ array | `TypeError` | `"items ต้องเป็น array — แต่ได้รับ object"` |
| เรียกค่าที่ควรเป็น function แต่ไม่ใช่ | `TypeError` | `"callback ต้องเป็น function"` |
| จำนวนสินค้าน้อยกว่า 1 หรือมากกว่า limit | `RangeError` | `"quantity ต้องอยู่ระหว่าง 1 ถึง 100 — แต่ได้รับ 0"` |
| อายุติดลบหรือเกิน 150 | `RangeError` | `"age ต้องอยู่ระหว่าง 0 ถึง 150 — แต่ได้รับ -5"` |
| เปอร์เซ็นต์เกิน 100 หรือน้อยกว่า 0 | `RangeError` | `"percent ต้องอยู่ระหว่าง 0 ถึง 100 — แต่ได้รับ 150"` |
| ความยาว string เกินกำหนด | `RangeError` | `"ชื่อผู้ใช้ต้องไม่เกิน 30 ตัวอักษร — ตอนนี้ 42 ตัว"` |
| ข้อมูลเป็นค่าว่างทั้งที่จำเป็นต้องมี | `Error` | `"name ห้ามเป็นค่าว่าง — กรุณากรอกชื่อ"` |
| กฎธุรกิจไม่ผ่าน | `Error` | `"ยอดเงินไม่พอ — มี 500 บาท แต่ต้องการถอน 1000"` |
| รูปแบบข้อมูลไม่ถูกต้อง (ที่ไม่เกี่ยวกับ type) | `Error` | `"email ต้องมี @ — รูปแบบอีเมลไม่ถูกต้อง"` |
| สถานะของระบบไม่ถูกต้อง | `Error` | `"ยังไม่ได้เข้าสู่ระบบ — กรุณา login ก่อน"` |
| JSON parse ไม่ผ่าน — ต้องการ throw เอง | `Error` | `"ข้อมูล JSON ไม่ถูกต้อง — Unexpected token"` |
| ตัวแปรไม่มีค่า (undefined) | `TypeError` หรือ `Error` | `"userId is required — received undefined"` |
- **ท่องจำ 3 ตัวที่ throw เองได้**: `Error`, `TypeError`, `RangeError` — ครอบคลุมทุกสถานการณ์
- **3 คำถามเลือก Error Type**: type? → TypeError / range? → RangeError / อื่น ๆ? → Error
- **ห้าม throw**: `SyntaxError` (parse-time), `ReferenceError` (scope resolution) — ปล่อยให้ JavaScript engine จัดการ
- **message สำคัญเสมอ**: ไม่ว่าจะเลือก Error type อะไร — message ต้องบอกว่าอะไรผิด, ค่าที่ได้รับ, และควรแก้อย่างไร
- **ดู `.name` ใน catch**: การเลือก Error type ที่ถูกต้องทำให้ catch แยกประเภท error ได้ — นี่คือประโยชน์ที่จับต้องได้ของการตัดสินใจที่ดี
- **เมื่อไม่แน่ใจ → `Error`**: การโยน `Error` ที่ message ดี ดีกว่าการโยน TypeError หรือ RangeError ผิดที่ — ปลอดภัยไว้ก่อน
- **ฝึกต่อไปใน Workshop**: บทถัดไปคือ Workshop ที่จะให้คุณได้ลองใช้ทุกสิ่งที่เรียน — ทั้ง Error, TypeError, RangeError, throw, try...catch, และการเลือก Error type ให้เหมาะกับสถานการณ์
การเลือก Error type ไม่ใช่แค่เรื่องของ syntax — มันคือการ**ออกแบบวิธีสื่อสารข้อผิดพลาดในโค้ดของคุณ** ให้คนที่มาเจอ error (รวมถึงตัวคุณเองในอนาคต) เข้าใจปัญหาได้เร็วที่สุด คิดเสมอว่า: **error message คือข้อความที่คุณเขียนถึงตัวเองในอีก 6 เดือนข้างหน้า** — ทำให้มันชัดเจนพอที่คุณจะขอบคุณตัวเองที่เขียนไว้ดี บทถัดไปคือ Workshop — เตรียมใช้ทุกสิ่งที่เรียนมาในสถานการณ์จริง!