Custom Errors (ข้อผิดพลาดแบบกำหนดเอง) ช่วยให้จัดการข้อผิดพลาดได้ละเอียดและมีความหมายมากกว่า Error ธรรมดา โดยการสร้างคลาสที่ extends Error พร้อมเพิ่มฟิลด์ เช่น code, statusCode, details เพื่อใช้ใน error handling, logging, และ API response
ตัวอย่างโค้ด
<!DOCTYPE html>
<html lang="th">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Custom Errors</title>
<style>
body { font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; }
.result { font-size: 18px; font-weight: 500; color: rebeccapurple; }
</style>
</head>
<body>
<h1>Custom Errors ใน JavaScript</h1>
<div class="result"></div>
<button class="Btn">คลิกที่นี่</button>
<h3>กดปุ่มเพื่อสร้างและแสดง Custom Error</h3>
<script>
const resEle = document.querySelector(".result");
const btnEle = document.querySelector(".Btn");
class CustomError extends Error {
constructor(message) {
super(message);
this.name = "CustomError";
}
}
function test() {
throw new CustomError("ข้อผิดพลาดใหม่ถูกโยน");
}
btnEle.addEventListener("click", () => {
try {
test();
} catch (err) {
resEle.innerHTML += "err.name = " + err.name + "<br>";
resEle.innerHTML += "err.message = " + err.message + "<br>";
}
});
</script>
</body>
</html>
ผลลัพธ์

เมื่อกดปุ่ม "คลิกที่นี่":

โครงสร้าง Custom Error แบบครบครัน (Best Practice)
// Base class สำหรับแอปพลิเคชัน
class AppError extends Error {
constructor(message, options = {}) {
super(message, options); // ES2022: options.cause
this.name = this.constructor.name;
this.code = options.code || "APP_ERROR";
this.statusCode = options.statusCode || 500;
this.isOperational = options.isOperational ?? true; // คาดการณ์ได้หรือไม่
this.details = options.details ?? null;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, this.constructor);
}
}
}
// Specific errors
class ValidationError extends AppError {
constructor(message, details) {
super(message, { code: "VALIDATION_ERROR", statusCode: 400, details });
}
}
class AuthenticationError extends AppError {
constructor(message = "Unauthorized") {
super(message, { code: "AUTH_ERROR", statusCode: 401 });
}
}
class NotFoundError extends AppError {
constructor(resource) {
super(`${resource} not found`, { code: "NOT_FOUND", statusCode: 404 });
}
}
class DatabaseError extends AppError {
constructor(message, originalError) {
super(message, {
code: "DB_ERROR",
statusCode: 500,
isOperational: false, // bug จริง ไม่ใช่ business logic
cause: originalError
});
}
}
การใช้งานใน Express.js / API
app.use((err, req, res, next) => {
if (err instanceof AppError) {
return res.status(err.statusCode).json({
error: {
code: err.code,
message: err.message,
details: err.details
}
});
}
// Programming error / unknown
console.error("UNHANDLED ERROR:", err);
res.status(500).json({ error: { code: "INTERNAL_ERROR", message: "Internal server error" } });
});
Error Cause (ES2022) — Error Chaining
try {
await db.query(sql);
} catch (dbErr) {
// ห่อหุ้ม error ต้นทางไว้ใน cause
throw new DatabaseError("Query failed", dbErr);
}
// ตอน catch ด้านนอก
try {
await service.doSomething();
} catch (err) {
console.log(err.cause); // เข้าถึง error ต้นทางได้
}
ข้อดีของ Custom Errors
- แยก Operational Errors (คาดการณ์ได้: validation, not found) กับ Programmer Errors (bug: null reference, syntax)
- ส่งข้อมูลโครงสร้างไปยัง frontend / monitoring ได้
- Filter / Handle ได้เฉพาะเจาะจงด้วย
instanceof - Stack trace ชัดเจน ชี้จุดที่โยนจริง