Plenty of π
Module 6: Errors, Debugging, and Troubleshooting
Custom Error Messages

When you throw an error, you can provide custom messages to make debugging easier and give more specific feedback to users or other developers.

Throwing a string (simple, but less informative):

function checkValue(value) {
  if (value > 100) {
    throw "Value exceeds maximum limit of 100!";
  }
  return value;
}

try {
  checkValue(150);
} catch (e) {
  console.error(e); // Output: Value exceeds maximum limit of 100!
}

Throwing an Error object (recommended): Using the built-in Error constructor (or specific error types like TypeError, RangeError) is better because these objects have standard properties like name and message, and often a stack trace.

function processData(data) {
  if (!data || typeof data.id === 'undefined') {
    throw new Error("Invalid data object: 'id' property is missing.");
  }
  console.log("Processing data ID: " + data.id);
}

try {
  processData({ name: "Test" });
} catch (e) {
  console.error("Error Name: " + e.name);
  console.error("Error Message: " + e.message);
  // console.error("Stack Trace: " + e.stack);
}
// Output:
// Error Name: Error
// Error Message: Invalid data object: 'id' property is missing.

Creating Custom Error Classes (Advanced): For more complex applications, you can create your own error classes by extending the built-in Error class. This allows you to define specific types of errors relevant to your application domain.

class NetworkError extends Error {
  constructor(message) {
    super(message);
    this.name = "NetworkError";
  }
}

try {
  // Simulate a network issue
  throw new NetworkError("Failed to connect to the server.");
} catch (e) {
  if (e instanceof NetworkError) {
    console.warn("Network issue detected: " + e.message);
  } else {
    console.error("An unexpected error occurred: " + e.message);
  }
}

Custom errors improve code organization and allow for more specific catch blocks.