【WEB】Typescript如何让一个classA在继承classB的同时拥有一个公共classC的方法和属性

56 阅读2分钟

题记

大家写项目的时候会不会经常遇到这么一个问题。 B ClassB2 Class分别继承至 A ClassA2 Class,但是因为BB2又希望有共同的一些方法和属性。请问大家一般怎么扩展这个结构?

image.png

可能大家会想,那还不简单,A ClassA2 Class共同在继承一个 Super A Class就好了。对,这样是可以的,可问题是,如果这个A ClassA2 Class不是项目中的,而是依附于的第三方依赖,又或者它们就是出于某些原因,你无法去改变AA2的继承链和数据结构,你又如何是好?

那要不退而求其次?让BB2里面用一个属性去连接到C?但是那样的话调用链就变成了 B.C.xxx()了。暂且不说使用上好不好使吧,如果你想要覆盖C的某个方法的实现,你又该如何是好?

可能还有朋友通过装饰器来实现,但是装饰器实现后的代码提示相关的可真是不好使呀。

基于上述问题,我分享个小经验给大家.

实现

基于TypeScript的mixin来实现。

混入的用法:> www.typescriptlang.org/docs/handbo…

我们将C Class变成一个mixin函数,然后通过泛型约束来设置可以混入进AA2.


type AConstructor = new (...args: any[]) => A
type A2Constructor = new (...args: any[]) => A2


export function CClass<
    T extends AConstructor | A2Constructor
>(base: T){


    return class CClass extends base {
    
    
        /** 在这里就可以为C class 添加特定的扩展函数或者属性了 */
        
        name:string
        age:number
        
        
        getAge(){
        return 18;
        }
        
        get name(){
            return "Hello";
        }
    }
}

然后,我们在BB2的继承那进行简单的修改。


//原版====>
class B extends A{

    ...
}
/// 修正为==>
class B extends CClass(A){
    ...
}

然后就可以愉快的使用B的调用在C上面扩展的函数和方法啦~

遗留问题

通过mixin这样实现后,CClass中没法设置private变量可怎么处理?

方案一:

export function CClass<
    T extends AConstructor | A2Constructor
>(base: T){
    
    // 在这里定义一些私有变量使用
    //---BEGIN
    const name:string = 'Hello';
    //----END
    return class CClass extends base {
    
    
        /** 在这里就可以为C class 添加特定的扩展函数或者属性了 */
        
        name:string
        age:number
        
        
        getAge(){
        return 18;
        }
        
        get name()=>name;
    }
}

方案二

使用 # 修饰符在属性和方法前面。这样也可以将属性和函数声明为私有的。

export function CClass<
    T extends AConstructor | A2Constructor
>(base: T){
 
    return class CClass extends base {
    
        //私有变量
        #name:string
   
        //私有方法
        get #name()=> #name;
    }
}

PS

最后如果大家有什么好的建议,还请不吝赐教😋

Bye~