Creating Error type
APIError factory creation
Overview
Extending globalThis.Error have multiple drawbacks :
- Matching on errors relies on
instanceofwhich have some limitations (ex:iframe) - Can be verbose even for adding just one property
The @w5s/error package helps creating type safe errors :
- Easy declaration extending
ErrorClass - Type safe matching on
name - Discourage matching using
instanceof
Declaring a new type
import { ErrorClass } from '@w5s/error';
// ┌─ ✓ PascalCase
// │ ✓ Name + 'Error'
// │ ┌─ Extends from ErrorClass()
export class {{SomeError}} extends ErrorClass({
errorName: '{{SomeError}}'; // <- Required
// errorMessage: 'This is an error message', // <- Optional
})<{
// ↓ Extra properties
// myProperty: string;
}> {}
Example 1 : Basic
import { ErrorClass } from '@w5s/error';
export class BasicError extends ErrorClass({
errorName: 'BasicError',
})<{}> {}
// Create an instance with :
//
// new BasicError();
// new BasicError({ message: 'Custom message' });
Example 2 : Advanced with extra properties
import { ErrorClass } from '@w5s/error';
export class AdvancedError extends ErrorClass({
errorName: 'AdvancedError',
errorMessage: 'Advanced error occurred',
})<{
customProperty: string;
}> {}
// Create an instance with :
//
// new AdvancedError({
// message: 'This is a message',
// customProperty: 'custom',
// cause: new TypeError('This is the cause')
// })
Matching errors
The recommended way to match on errors created with ErrorClass is to use a switch / case on the error name
class FooError extends ErrorClass({ errorName: 'FooError' })<{ fooProperty: string; }> {};
class BarError extends ErrorClass({ errorName: 'BarError' })<{ barProperty: number; }> {};
function parse(): Result<string, FooError | BarError> {
//...
}
function program() {
const result = parse();
if (Result.isError(result)) {
switch (result.name) {
case FooError.errorName: {
console.log('FooError:', error.fooProperty);
break;
}
case BarError.errorName: {
console.log('BarError:', error.barProperty);
break;
}
default: assertNever(result.name);
}
}
}
Caused / Specializing error
CustomError can be used to create specific errors with a cause property that is useful to keep track of the chain of errors.
class CauseError extends ErrorClass({ errorName: 'CauseError' })<{}> {};
try {
// ...
// return Result.Ok();
} catch (error) {
return Result.Error(new CauseError({
message: 'This is a better error',
cause: error, // <- The cause property can be any type but preferably an error object.
}));
}