Attempting to create a custom Error class that can handle different data based on the error code seemed like a complex task for TypeScript. However, surprisingly, it was successful:
const enum ERROR_CODES {
E_AUTHORIZATION = 'Authorization error',
E_REQUEST = 'Request failed',
E_INVALID = 'Invalid data',
}
interface ERROR_TYPES {
[ERROR_CODES.E_AUTHORIZATION]: string
[ERROR_CODES.E_REQUEST]: { url: string; status: number }
[ERROR_CODES.E_INVALID]: { action: string; field: string }
}
class MyError<TError extends ERROR_CODES> extends Error {
constructor(
public readonly code: TError,
public readonly data: ERROR_TYPES[TError],
) { super(code) }
}
Usage example:
throw new MyError(ERROR_CODES.E_AUTHORIZATION, 'whatever')
throw new MyError(ERROR_CODES.E_AUTHORIZATION, {
operation: 'login',
field: 'email',
})
The above examples work as expected. Creating error codes that do not require any data led me to this:
const enum ERROR_CODES {
// ...
E_UNKNOWN = 'Unknown error'
}
interface ERROR_TYPES {
// ...
[ERROR_CODES.E_UNKNOWN]: void
}
Interestingly, TypeScript behaves unexpectedly when attempting to create an error with just one argument:
throw new MyError(ERROR_CODES.E_UNKNOWN, undefined)
This works. However, if we try this:
throw new MyError(ERROR_CODES.E_UNKNOWN)
An error Expected 2 arguments, but got 1.
is thrown. Even using void 0
:
throw new MyError(ERROR_CODES.E_UNKNOWN, void 0)
Which should be equivalent to the first example, results in
Expected 'undefined' and instead saw 'void'.
. What exactly is causing this behavior and is there a way to make the second example work with just one argument?