有个奇怪的需求,对项目中存在的不同的类,给它们扩展出一个相同的方法,以供消费者调用。也就是说,要求从原来的类派生出来的新类,除了拥有原来类的方法外,还额外多出了一个新的通用方法。

比如对于这样两个类,假如可以通过一个名字叫做 genericExtend() 的函数扩展,那么其扩展出的新类会多出一个 genericMethod 方法: typescript class A { a() { // ... } }

class B { b() { // ... } }

const instanceofA = new (genericExtend(A))() const instanceofB = new (genericExtend(B))()

instanceofA.a() // ok instanceofA.genericMethod() // ok

instanceofB.b() // ok instanceofB.genericMethod() // ok

这个需求看起来很奇怪,但也不是完全不合理,比如原始的 A 和 B,甚至 C 以及 D 等等类,是第三方来的依赖,虽然不完全一样,但是又有一些类似的地方,可以被通用处理。同时项目中又大量存在直接调用它们的原始方法的地方,不能全部替换,因此,可以将这些实例替换为被扩展后的实例,由于被扩展后的实例是原始类的子类,所以原有调用不用改变。而对于新的希望应用通用处理逻辑的地方,可以直接调用新的方法 genericMethod()。

一个幼稚的实现

具体实现如下:

typescript type Constructor = new (...args: any[]) => any

function genericExtend(target: T) { return class GenericExtended extends target { constructor(...args: any[]) { super(...args) }

genericMethod() {
  ...
}

} }

这个实现完全能满足最初提出的需求,并且,可以通过联合类型,实现静态类型检查,比如对 instanceofA 定义一个联合类型,那么无论调用原始方法还是新的通用方法,都能享受到静态类型的约束: typescript const instanceofA: GenericExtended & A = new (genericExtend(A))() const instanceofB = new (genericExtend(B))()

instanceofA.a() // ok,有代码智能提示 instanceofA.genericMethod() // ok,有代码智能提示

instanceofB.b() // ok,不报错,但是没有静态类型检查 instanceofB.genericMethod() // ok,不报错,但是没有静态类型检查

幼稚实现不好的地方

虽然幼稚的实现完全能够工作,并且我将它用在了实际的工程里,但是它有这些缺点:

  • 在实现上使用了 any 关键字
  • 在声明实例的类型时,需要使用联合类型的方式,比较丑
  • 不显式声明类型,就没有类型检查,没有触发 TypeScript 的类型自动推断

不知道这个需求会不会是某种通用模式?从而有现成的更加优雅的实现方案?可能受制于自己的认知,网上搜索了很久,没有找到优雅的通用的实现。希望有高人能指点指点。