This question shares similarities with another post I made, but this time focusing on using classes instead of plain objects.
class Exception1 extends Error {
constructor(message: string, public arg1: string) {
super(message);
}
}
class Exception2 extends Error {
constructor(message: string, public arg2: string) {
super(message);
}
}
type MyException = Exception1 | Exception2;
type Constructor<T> = new (...args: any) => T;
function filterExceptions<E extends MyException>(exceptions: MyException[], classes?: Constructor<E>[]): E[] {
if (!classes) return exceptions as E[];
return exceptions.filter((exception) => classes.some((klass) => exception instanceof klass)) as E[];
}
const ex1 = new Exception1("ex1", "whatever");
const ex2 = new Exception2("ex2", "whatever");
const exceptions = [ex1, ex2]
const f1 = filterExceptions(exceptions); // OK
const f2 = filterExceptions(exceptions, [Exception1]); // OK
const f3 = filterExceptions(exceptions, [Exception1, Exception2]) // Error
Also accessible at Typescript playground.
The error message states:
Types of construct signatures are incompatible.
Type 'new (message: string, arg2: string) => Exception2' is not assignable to type 'new (...args: any) => Exception1'.
Property 'arg1' is missing in type 'Exception2' but required in type 'Exception1'.(2419)
I found a temporary solution by specifying the generic parameter during the function call:
const f3 = filterExceptions<Exception1 | Exception2>(exceptions, [Exception1, Exception2])
However, this is not an ideal approach.
PS. Removing extra constructor arguments in Exception1
and Exception2
eliminates the error, but causes f3
to be typed as Exception1[]
instead of (Exception1 | Exception2)[]