具有默认属性值的Typescript mixins(从新的MyClass派生)

时间:2019-02-09 16:10:19

标签: typescript mixins

我正在使用Typescript进行一些混入实验,并且已经掌握了一些构建混入方法的基础知识。在所有这些错误中,我都会遇到相同的错误。

这是我的mixin类:

export class OnDestroyMixin implements OnDestroy {

    public destroyStream: Subject<void> = new Subject();

    ngOnDestroy(): void {
        console.log(`on destroy from mixin`);

        this.destroyStream.next();
        this.destroyStream.complete();
    }
}

并且每当调用on destroy函数时(将其混合到另一个类中之后)this.destroyStream不存在,所以我遇到了Cannot read property 'next' of undefined错误。

我已经考虑过在构造函数中进行设置,但是我也不知道构造函数如何在mixins中工作...

我认为这应该可行。

我当前使用的mixin方法是mixin装饰器:

export function Mixin(baseCtors: Function[]) {
    return function (derivedCtor: Function) {
        baseCtors.forEach(baseCtor => {
            Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
                const descriptor = Object.getOwnPropertyDescriptor(baseCtor.prototype, name);

                if (name === 'constructor')
                    return;

                if (descriptor && (!descriptor.writable || !descriptor.configurable || !descriptor.enumerable || descriptor.get || descriptor.set)) {
                    Object.defineProperty(derivedCtor.prototype, name, descriptor);
                } else {
                    derivedCtor.prototype[name] = baseCtor.prototype[name];
                }

            });
        });
    };
}

我是从网上某个地方复制的,但是正如我所说,我尝试了几种不同的方法,所有这些方法实际上都是将属性从一个原型复制到另一个原型。

2 个答案:

答案 0 :(得分:0)

此问题的根本原因是,当您在类中定义属性值时将其转换为JavaScript this value is set in the constructor。上面的mixin代码专门忽略了构造函数。真正的解决方案是将2个类的构造函数合并在一起。

在Typescript中,似乎有2种不同的混合方法。类似于我问题中的一种方法,其中我们遍历原型属性并将它们从一个类复制到另一个类,而我们只需return a new class that extends the original

function Flies<TBase extends Constructor>(Base: TBase) {
    return class extends Base {
        fly() {
            alert('Is it a bird? Is it a plane?');
        }
    };
}

我以为我将无法在angular中使用它,因为它是一个返回新类的函数,但是完全有可能证明here

class SourceClass{}

@Component({
    selector: 'some-selector',
    templateUrl: './some-selector.html',
    styleUrls: ['./some-selector.scss']
})
export class SampleMixedClass extends Flies(SourceClass) {}

答案 1 :(得分:0)

如我先前的回答中所述,问题是属性的值在mixin类的构造函数中设置,而构造函数在mixin装饰器中被忽略。

解决此问题的另一种方法是不在构造函数中设置属性值,而是使用getter和setter定义属性:

export class OnDestroyMixin implements OnDestroy {
    private _destroyStream: Subject<boolean>;

    public get destroyStream(): Subject<boolean>{
        let stream = this._destroyStream;

        if(stream == null){
            stream = new Subject<boolean>();
            this._destroyStream = stream;
        }

        return stream;
    }


    public ngOnDestroy(): void {
        this.destroyStream.next();
        this.destroyStream.complete();
    }
}

实际上,在这种情况下,不需要设置器,因为只读值会有所帮助。当我们使用吸气剂时,这不是常规属性,并且未在构造函数中设置。相反,我们使用getter函数定义属性。将其复制到mixin装饰器中。