TypeScript:如何委托接口方法

TypeScript: How to delegate interface methods

我有一个来自第三方库的类似这样的界面:

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>;
}

我想将接口方法委托给相同类型的实现,如下所示:

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);
  }
}

我不知道如何正确实现委托,所以调用了正确的 impl 方法。

都没有TypeScript function overloading 也没有 Is there a way to do method overloading in TypeScript? 正在帮助我做出正确的授权。

不是最佳解决方案,但仍有一些解决方法:

interface MyInterface {
   foo(arg: string): string
   foo(arg: number): number
}

class Foo implements MyInterface {
   foo(arg: string): string;
   foo(arg: number): number;
   // foo(arg: number): string; -> error, if you uncomment this line, please comment line above

   foo(arg: string | number) {
      if (typeof arg === 'string') {
         return arg
      }
      return 12 as number
   }
}

const result = new Foo().foo(2)

坏消息:您应该编写所有重载。据我所知,用重载映射接口是不可能的

好消息:如果你提供与实现的接口不兼容的函数重载,TS 会抱怨。

更新

还有另一种方法。

您可能不需要将 Foo class 扩展 MyInterface

interface MyInterface {
   foo(arg: string): string
   foo(arg: number): number
}

class Foo {
   foo(arg: string): string;
   foo(arg: number): number;
   foo(arg: string | number) {
      if (typeof arg === 'string') {
         return arg
      }
      return 12 as number
   }
}

// sorry, I can't find the link to the author of this type utility
type DeepEqual<X, Y> =
   (<T>() => T extends X ? 1 : 2) extends
   (<T>() => T extends Y ? 1 : 2) ? true : false;

/**
 * Here you can just check if types are deep equal or not
 * Try to change overloadings for `foo` method and you
 * will see that Result type will be falsy
 */
type L = Deep<Foo, MyInterface>

当方法调用应该委托给类似的方法签名时,委托的方法可以决定如何处理给定的参数。

重载方法签名归结为最通用的重载(与静态类型语言有些不同)。因此,不需要实现接口中声明的更具体的方法,但可以在实现接口的 class 中包含声明作为编译器提示。在这种情况下,rest 又名 vararg 参数 (...arg:any[]) 派上用场,因为它呈现通用方法签名。

 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);
  }
}