I have this ugly looking type, which basically just removes methods and makes stack
optional:
type SerializedError<T extends Error> = Omit<
T,
| Required<{
[K in keyof T]: T[K] extends CallableFunction ? K : never;
}>[keyof T]
| 'stack'
> & {
stack?: string | undefined;
} extends infer U
? { [K in keyof U]: U[K] }
: never;
And I have this custom error class:
export class ApiError extends Error {
public override stack: string = '';
public constructor(reason: any) {
const { name, message, stack } = reason;
super(typeof message === 'string' ? message : String(reason));
this.name = typeof name === 'string' ? name : this.constructor.name;
typeof stack === 'string'
? (this.stack = stack)
: Error.captureStackTrace(this, this.constructor);
}
public serialize(includeStack: boolean = false): SerializedError<this> {
const classKeys = Object.keys(this) as (keyof this)[];
const serializableKeys = classKeys.filter((key) => {
const isMethod = typeof this[key] === 'function';
const isStack = key === 'stack';
return !isMethod && (!isStack || includeStack);
}) as (keyof SerializedError<this>)[];
return serializableKeys.reduce((acc, key) => {
acc[key] = this[key]; // Type 'keyof SerializedError<this>' cannot be used to index type 'this'
return acc;
}, {} as SerializedError<this>);
}
}
I wanna use SerializedError<this>
for ApiError
‘s serialize
method, like shown above, so it would work for any class extending ApiError
. But typescript doesn’t let me to do that as shown in the code snippet comment.
But when I change this
with ApiError
, error is gone:
public serialize(includeStack: boolean = false): SerializedError<ApiError> {
const classKeys = Object.keys(this) as (keyof ApiError)[];
const serializableKeys = classKeys.filter((key) => {
const isMethod = typeof this[key] === 'function';
const isStack = key === 'stack';
return !isMethod && (!isStack || includeStack);
}) as (keyof SerializedError<ApiError>)[];
return serializableKeys.reduce((acc, key) => {
acc[key] = this[key]; // No error
return acc;
}, {} as SerializedError<ApiError>);
}
So the question is why this
and ApiError
in the given context aren’t the same, and is there any way to make it work (maybe with different approach)?