Working with Custom Error Types
Defining and using custom error types with go-errors.
Working with Custom Error Types
go-errors
allows you to define and use your own custom error types. This is highly recommended for creating robust and maintainable applications. Custom error types provide several benefits:
- Improved Type Safety: You can use TypeScript's type system to distinguish between different types of errors.
- Better Error Handling: You can handle specific error types differently, providing more granular error handling logic.
- Contextual Information: You can add properties to your custom error types to store additional context about the error (e.g., the field that failed validation, the HTTP status code, etc.).
- Clearer Code: Custom error types make your code more readable and self-documenting.
Defining Custom Error Types
The recommended way to define custom error types is to create classes that extend the built-in Error
class.
// Basic custom error class
class MyCustomError extends Error {
constructor(message: string) {
super(message);
this.name = 'MyCustomError'; // Important: Set the 'name' property
}
}
// Custom error with additional context
class ValidationError extends Error {
constructor(message: string, public field: string) {
super(message);
this.name = 'ValidationError';
}
}
// Custom error with a hierarchy
class ApiError extends Error {
constructor(message: string, public status: number) {
super(message);
this.name = 'ApiError';
}
}
class NotFoundError extends ApiError {
constructor(message: string, public resourceId: string) {
super(message, 404);
this.name = 'NotFoundError';
}
}
Key Points:
- Extend
Error
: Always extend the built-inError
class. - Set
name
: Set thename
property of your custom error class. This is crucial for distinguishing between different error types, especially when usinginstanceof
. - Add Context: Add properties to your custom error classes to store relevant context, such as the field that caused a validation error, an HTTP status code, or a resource ID.
goSync
and go
Using Custom Error Types with You can use your custom error types with goSync
and go
by specifying them as the E
type parameter in the Result<T, E>
type.
import { goSync, go } from 'go-errors';
// Using goSync with a custom error
let [result, err] = goSync<string, ValidationError>(() => {
if (input.length < 5) {
throw new ValidationError("Input is too short", "inputField");
}
return input.toUpperCase();
});
if (err) {
console.error("Validation Error:", err.message, "Field:", err.field);
} else {
console.log("Result:", result);
}
// Using go with a custom error hierarchy
async function fetchData(): Promise<string> {
const response = await fetch('/api/data');
if(!response.ok) {
if(response.status === 404) {
throw new NotFoundError("Resource not found", "some-resource-id");
} else {
throw new ApiError("API request failed", response.status);
}
}
return response.text();
}
async function main() {
let [data, err] = await go<string, ApiError>(fetchData());
if(err) {
if(err instanceof NotFoundError) {
console.error("Resource not found:", err.message, "Resource ID:", err.resourceId);
} else if (err instanceof ApiError) {
console.error("API Error:", err.message, "Status:", err.status);
} else {
console.error("An unexpected error occurred:", err); // This should never happen with proper type definitions
}
} else {
console.log("Data:", data);
}
}
main();
goFetch
Using Custom Error Types with The errorTransformer
option in goFetch
is particularly useful for working with custom error types. You can use it to transform raw errors (like Response
objects from fetch
) into your custom error types.
import { goFetch } from 'go-errors';
let [data, err] = await goFetch<MyData, ApiError>('/api/data', {
errorTransformer: (error) => {
if (error instanceof Response) {
return new ApiError(`HTTP Error: ${error.status}`, error.status);
}
if (error instanceof Error) {
return new ApiError(error.message, 500); // Default to 500 for other errors
}
return new ApiError("An unknown error occurred", 500);
},
});
if (err) {
console.error("API Error:", err.message, "Status:", err.status);
}
Best Practices
- Create Specific Error Types: Create error types that are specific to your application's domain and error scenarios (e.g.,
ValidationError
,AuthenticationError
,DatabaseError
,NetworkError
). - Use Error Hierarchies: Consider creating error hierarchies (e.g., a base
AppError
class with more specific subclasses) to organize your error types and handle them at different levels of granularity. - Add Contextual Information: Include relevant properties in your custom error types to provide more context for debugging and error reporting.
- Use
instanceof
: Useinstanceof
to check the type of an error and handle it accordingly. - Consistent Transformation: Use the
errorTransformer
ingoFetch
to consistently transform API errors into your custom error types.
See Also
- Error Handling in go-errors: Learn more about general error handling principles.
- The Result Type: Understand the
Result
type. - Core Functions Overview: Get an overview of
goSync
,go
, andgoFetch
.