TypeScript 实现对不同类的通用扩展

共 1771字,需浏览 4分钟

 ·

2021-05-28 21:19

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


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


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()。


一个幼稚的实现


具体实现如下:


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


function genericExtend<T extends Constructor>(target: T) {

  return class GenericExtended extends target {

    constructor(...args: any[]) {

      super(...args)

    }


    genericMethod() {

      ...

    }

  }

}


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


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 的类型自动推断

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


浏览 21
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报