Looking to develop a function that can accept an optional errorCallback
parameter. In cases where the consumer of this function does not provide a callback, I aim to default to a preset handler. The key criteria here are strong typing and utilizing the return type defined by the consumer's custom errorCallback
, falling back on my tailored error handler's return type when necessary.
Below you'll find the code snippet:
export enum ErrorType {
VALIDATION_ERROR,
API_ERROR,
UNKNOWN_ERROR,
UNAUTHORIZED
}
type MockZodType ={}
type MockResponseError = {}
export type ServiceError<TSchema extends MockZodType> =
| {
type: ErrorType.VALIDATION_ERROR;
message: string;
status: number;
data: TSchema;
originalError: MockResponseError;
}
| {
type: ErrorType.API_ERROR;
message: string;
status: number;
data: unknown;
originalError: MockResponseError;
}
| {
type: ErrorType.UNKNOWN_ERROR;
message: string;
status: number;
data: unknown;
originalError: unknown;
}
| {
type: ErrorType.UNAUTHORIZED;
message: string;
status: number;
data: unknown;
preventDefaultHandler: boolean;
originalError: MockResponseError;
};
export type ServiceCallOptions<
TServiceCallReturn extends Promise<unknown>,
TSchema extends MockZodType = never,
TErrorCallbackReturn extends Promise<unknown> = Promise<ServiceError<TSchema>>
> = {
serviceCall: () => TServiceCallReturn;
errorSchema?: TSchema;
errorCallback?: (e: ServiceError<TSchema>) => TErrorCallbackReturn;
};
export async function callService<
TServiceCallReturn extends Promise<unknown>,
TSchema extends MockZodType = never,
TErrorCallbackReturn extends Promise<unknown> = Promise<ServiceError<TSchema>>
>({
serviceCall,
errorSchema,
errorCallback = async (e)=> {
if (e.type === ErrorType.UNAUTHORIZED && !e.preventDefaultHandler) {
// some custom default handler;
}
return e;
}
}: ServiceCallOptions<TServiceCallReturn, TSchema, TErrorCallbackReturn>) {
// some logic
}
An error emerges from the default value in the errorCallback
parameter with the following message:
Type '(e: ServiceError<TSchema>) => Promise<ServiceError<TSchema>>' is not assignable to type '(e: ServiceError<TSchema>) => TErrorCallbackReturn'.
Type 'Promise<ServiceError<TSchema>>' is not assignable to type 'TErrorCallbackReturn'.
'Promise<ServiceError<TSchema>>' is assignable to the constraint of type 'TErrorCallbackReturn', but 'TErrorCallbackReturn' could be instantiated with a different subtype of constraint 'Promise<unknown>'.
No interest in using overloads, so why does it fail to work as expected?
To test or revise the code, check out the ts playground.