[SOLVED] Overloading decorator cause 'This overload signature is not compatible with its implementation signature'

Issue

I’m working on decorators for my API methods and I encoutered this problem. I’m trying to overload decorators and get the ‘This overload signature is not compatible with its implementation signature’ error lintered.

Here goes fragment of code I created:

export function ApiMethod<TResponse extends ApiResponse>(options: { methodName: string }): 
    (target: any, propertyName: string, descriptor: TypedPropertyDescriptor<() => Promise<TResponse>>) => void    

export function ApiMethod<TResponse extends ApiResponse>(options: { methodName: string, accessPolicy: MethodAccessPolicy }): 
    (target: any, propertyName: string, descriptor: TypedPropertyDescriptor<(payload: JwtPayload) => Promise<TResponse>>) => void   

export function ApiMethod<TParams extends Object, TResponse extends ApiResponse>(options: { methodName: string, paramsType: (new (...args: Array<any>) => TParams) }): 
    (target: any, propertyName: string, descriptor: TypedPropertyDescriptor<(params: TParams) => Promise<TResponse>>) => void  
 
// Here is the error   
export function ApiMethod<TParams extends Object, TResponse extends ApiResponse>(options: { methodName: string, paramsType: (new (...args: Array<any>) => TParams), accessPolicy: MethodAccessPolicy }): 
    (target: any, propertyName: string, descriptor: TypedPropertyDescriptor<(params: TParams, payload: JwtPayload) => Promise<TResponse>>) => void   

export function ApiMethod<TParams extends Object, TResponse extends ApiResponse>(options: MethodOptions | ParameterizedMethodOptions<TParams>): 
    (target: any, propertyName: string, descriptor: TypedPropertyDescriptor<(params?: TParams, payload?: JwtPayload) => Promise<TResponse>>) => void    
{
    return (target: any, propertyName: string, descriptor: TypedPropertyDescriptor<(params?: TParams, payload?: JwtPayload) => Promise<TResponse>>) => {
        
    };
}

interface MethodOptions {
    methodName: string;
    accessPolicy?: MethodAccessPolicy;
}

interface ParameterizedMethodOptions<TParams> extends MethodOptions {
    paramsType?: (new (...args: Array<any>) => TParams);
}

I set this general restriction like that so the decorated method can have either params or payload or both, depending on which overload you do use:

(target: any, propertyName: string, descriptor: TypedPropertyDescriptor<(params?: TParams, payload?: JwtPayload) => Promise<TResponse>>) => void

All the overloads are working – I can set no parameters whatsoever, only payload, only parameters, but I can’t set payload and parameters because of the error.

Any help would be appreciated. Thanks in advance.

Solution

You did not provide the type of JwtPayload and I assumed it was Record<string, any> which allowed me to reproduce the error.

This is because the return type of the failing overload is different from the implementation signature.

(target: any, propertyName: string, descriptor: TypedPropertyDescriptor<(params: TParams, payload: JwtPayload) => Promise<TResponse>>) => void  

Versus

(target: any, propertyName: string, descriptor: TypedPropertyDescriptor<(params?: TParams, payload?: JwtPayload) => Promise<TResponse>>) => void

You’ll have to union the return type:

export function ApiMethod<TParams extends Object, TResponse extends ApiResponse>(options: MethodOptions | ParameterizedMethodOptions<TParams>): 
    ((target: any, propertyName: string, descriptor: TypedPropertyDescriptor<(params: TParams, payload: JwtPayload) => Promise<TResponse>>) => void) | 
    ((target: any, propertyName: string, descriptor: TypedPropertyDescriptor<(params?: TParams, payload?: JwtPayload) => Promise<TResponse>>) => void) 
{
    return (target: any, propertyName: string, descriptor: TypedPropertyDescriptor<(params?: TParams, payload?: JwtPayload) => Promise<TResponse>>) => {
        
    };
}

Playground Link

As for why this happens, I believe it is because TParams is a generic while JwtPayload is not, and as such TS cannot guarantee JwtPayload is instantiated with the same type or intended type across overloads.

Answered By – Cody Duong

Answer Checked By – Candace Johnson (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *