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