typescriptproxy-pattern

TypeScript: How to delegate interface methods


I have an interface like this coming from an 3rd party lib:

MyInterface{
    foo(arg: string): Promise<any>;
    foo(arg: string, ...params: any[]): Promise<any>;

    foo<T>(arg: string): Promise<T>;
    foo<T>(arg: string, ...params: any[]): Promise<T>;

    bar(arg: string, callback?: (err: Error, row: any) => void): Promise<number>;
    bar(arg: string, ...params: any[]): Promise<number>;
}

And I want to delegate the interface methods to an implementation of the same type, like this:

MyClass implements MyInterface {

  private impl:MyInterface = ...
  
  foo(..) //how to do it right ??


  // TS2393: Duplicate function implementation.
  bar(arg: string, callback?: (err: Error, row: any) => void): Promise<number>{
     return impl.bar(sql,callback);
  }

  // TS2393: Duplicate function implementation.
  bar(arg, ...params: any[]): Promise<number>{
      return impl.bar(arg,params);
  }
}

I have no idea how to implement the delegation correctly, so the right impl methods are called.

Neither TypeScript function overloading Nor Is there a way to do method overloading in TypeScript? is helping me to make the correct delegation.


Solution

  • When method calls should be delegate to similar methods signatures, the delegated method can decide how to handle the given parameters.

    The overloaded method signatures boil down to the most generic overload (somewhat different to static typed languages). Therefore the more specific methods declared in the interface are not required to be implemented, but there declaration can be included in the class that implements the interface as a compiler hint. In this case the rest aka vararg parameter (...arg:any[]) comes in handy since it renders a generic method signature.

     class MyClass implements MyInterface {
       constructor(private delegate:MyInterface){}
    
      // these 2 methods below can't be declared in this class since they have
      // the same signature as the ones with <T> type argument (type-erasure?)   
      // foo(arg: string, ...params: any[]): Promise<any>;
      // foo(arg: string): Promise<any>; 
    
      //compiler hint, the method below will be called at runtime
      foo<T>(arg: string): Promise<T>;
      foo<T>(arg: string, ...params: any[]): Promise<T>{
        //we leave the responsibility to handle the given arguments to the `delegate` implementation 
        return this.delegate.foo(arg, ...params); 
      }
    
      // this method declaration has no implicit implementation, at runtime 
      // the more generic method below will be called, this method acts
      // as a compiler "hint" and can be ommitted
      bar(arg: string, callback?: (err: Error, row: any) => void): Promise<number>; 
      bar(arg, ...params: any[]): Promise<number>{
          return this.delegate.bar(arg,params);
      }
    }