TypeScript 混入

JavaScript和TypeScript都没有对混入进行内置的语法支持,但是通过js结构化的语言,想实现混入是很简单的。我们都知道类只支持扩展一个类,而混入就是让类支持多个扩展类,其中C++和python都是支持多继承的,而且相对语法扩展支持都比较完善。现在,本文章将使用TS实现一个简易版的混入:

先定义一个类型,相当于接口约束(主要约束类的结构):

type Constructor = new()=>{}

接下来,定义混入:

function mixin<T extends Constructor>(Base:T,...Classes:T[]):T {
    Classes.forEach(cls=>{
        Object.getOwnPropertyNames(cls.prototype).forEach((key:never)=>{ //获取实例方法
            if(!Base.prototype[key]){
                Base.prototype[key]=cls.prototype[key]
            }
        })

        Object.getOwnPropertyNames(new cls).forEach((key:never)=>{  //获取实例属性
            if(!Base.prototype[key]){
                Base.prototype[key]=new cls()[key]
            }
        })
    })

    return Base
}

在这个函数中,第一个参数接收需要扩展多个类的类,类型为上限为Constructor构造的类,因为要接受多个可扩展类,所以第二个参数使用剩余参数,允许用户放入多个类型上限为T的类,而mixin函数就是将所有传入的Classes类扩展到Base类,最后将扩展好的类返回出去。

接下来定义一些类:

class Base1 {
    public random=Math.random()
    public active():string{
        return "Hello active"
    }
}

class WithMixin {
    
}

我们姑且把Base系列类称作基类吧,WithMixin就是混入类

接下来,我们把这两个类当作参数传给mixin函数

let _mixin=mixin(WithMixin,Base1)

let $mixin=new _mixin()

$mixin.active() //报错!!!

此时如果你会发现使用active方法会报错,不对呀?我们输出$mixin原型看看:

 原型上是有active方法的,但是TS编译器会报错,这是因为WithMixin类中没有定义这个方法,但别忘记了,经过mixin函数返回出来的类的类型是继承自Constructor的,而Constructor没有active这个方法签名,TS编译器会认为这个行为是危险的,没事,当然你也可以把严格模式关了(狗头)。。。接下来我们在WithMixin和Constructor中分别定义这个函数签名:

写法一:
type Constructor = new()=>{
    active:()=>string, //定义这个签名所有该类型的构造方法内部都要实现这个方法
    random:number
}

//写法二:
type Constructor<T>=new()=>T


class WithMixin {
    public active:()=>string
    public random:number
}

$mixin.active() //'Hello active'


如果你想重写继承的active方法,直接再WithMixin中实现这个方法体即可。

现在就可以使用了!

当然还可以再WithMixin类中定义自己的属性,只不过要注意在Constructor中定义可选属性

type Constructor = new()=>{
    active:()=>string
    random:number

    myself?:()=>string //WithMixin类中的自带方法,标记为可选,否则在其他Constructor类中必须也定义这个方法
}


class WithMixin {
    public active:()=>string
    public random:number

    public myself():string{
       rteurn '混入自带方法'
    }
}

$mixin.myself() // '混入自带方法' 完全可以使用

现在我们来混入多个类: 

class Base2 {
    public random:number  //constructor中的非可选方法,都要定义签名
    public active:()=>string
    public base2:string='Base2类属性' 
}

//别忘了在constructor中定义base2属性
type Constructor = new()=>{
    active:()=>string
    random:number
    myself?:()=>string
    base2:string //定义后,才能在ts编译器通过使用
}

let _mixin=mixin2<Constructor>(withMixin,Base1,Base2) //扩展多个类Base1 Base2...
let $mixin=new _mixin()
$mixin.base2 //Base2类属性

这样一个简单的混入就实现了,但是这个还是有些问题的,比如静态方法、属性没办法实现,还有如果混入类中如果有重名属性的话,也没考虑如何调用,不过这些问题在python语言中都是有完美解决方案的,以后有时间再慢慢搞下,最近也是没啥时间。。。

再见! 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值