TypeScript 實(shí)現(xiàn)對(duì)不同類的通用擴(kuò)展
有個(gè)奇怪的需求,對(duì)項(xiàng)目中存在的不同的類,給它們擴(kuò)展出一個(gè)相同的方法,以供消費(fèi)者調(diào)用。也就是說,要求從原來的類派生出來的新類,除了擁有原來類的方法外,還額外多出了一個(gè)新的通用方法。
比如對(duì)于這樣兩個(gè)類,假如可以通過一個(gè)名字叫做 genericExtend() 的函數(shù)擴(kuò)展,那么其擴(kuò)展出的新類會(huì)多出一個(gè) 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
這個(gè)需求看起來很奇怪,但也不是完全不合理,比如原始的 A 和 B,甚至 C 以及 D 等等類,是第三方來的依賴,雖然不完全一樣,但是又有一些類似的地方,可以被通用處理。同時(shí)項(xiàng)目中又大量存在直接調(diào)用它們的原始方法的地方,不能全部替換,因此,可以將這些實(shí)例替換為被擴(kuò)展后的實(shí)例,由于被擴(kuò)展后的實(shí)例是原始類的子類,所以原有調(diào)用不用改變。而對(duì)于新的希望應(yīng)用通用處理邏輯的地方,可以直接調(diào)用新的方法 genericMethod()。
一個(gè)幼稚的實(shí)現(xiàn)
具體實(shí)現(xiàn)如下:
type Constructor = new (...args: any[]) => any
function genericExtend<T extends Constructor>(target: T) {
return class GenericExtended extends target {
constructor(...args: any[]) {
super(...args)
}
genericMethod() {
...
}
}
}
這個(gè)實(shí)現(xiàn)完全能滿足最初提出的需求,并且,可以通過聯(lián)合類型,實(shí)現(xiàn)靜態(tài)類型檢查,比如對(duì) instanceofA 定義一個(gè)聯(lián)合類型,那么無論調(diào)用原始方法還是新的通用方法,都能享受到靜態(tài)類型的約束:
const instanceofA: GenericExtended & A = new (genericExtend(A))()
const instanceofB = new (genericExtend(B))()
instanceofA.a() // ok,有代碼智能提示
instanceofA.genericMethod() // ok,有代碼智能提示
instanceofB.b() // ok,不報(bào)錯(cuò),但是沒有靜態(tài)類型檢查
instanceofB.genericMethod() // ok,不報(bào)錯(cuò),但是沒有靜態(tài)類型檢查
幼稚實(shí)現(xiàn)不好的地方
雖然幼稚的實(shí)現(xiàn)完全能夠工作,并且我將它用在了實(shí)際的工程里,但是它有這些缺點(diǎn):
在實(shí)現(xiàn)上使用了 any 關(guān)鍵字 在聲明實(shí)例的類型時(shí),需要使用聯(lián)合類型的方式,比較丑 不顯式聲明類型,就沒有類型檢查,沒有觸發(fā) TypeScript 的類型自動(dòng)推斷
不知道這個(gè)需求會(huì)不會(huì)是某種通用模式?從而有現(xiàn)成的更加優(yōu)雅的實(shí)現(xiàn)方案?可能受制于自己的認(rèn)知,網(wǎng)上搜索了很久,沒有找到優(yōu)雅的通用的實(shí)現(xiàn)。希望有高人能指點(diǎn)指點(diǎn)。
