【问题标题】:Typescript mixins with default property values (derived from new MyClass)具有默认属性值的 Typescript mixins(从新的 MyClass 派生)
【发布时间】:2019-07-03 14:50:22
【问题描述】:

我正在 Typescript 中试验一些 mixin,并且已经掌握了使用几种不同方法构建 mixin 的基础知识。在所有这些中,我都遇到了同样的错误。

这是我的 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];
                }

            });
        });
    };
}

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

【问题讨论】:

    标签: typescript mixins


    【解决方案1】:

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

    Typescript 中似乎有 2 种不同的 mixin 方法。类似于我的问题中的方法,我们遍历原型属性并将它们从一个类复制到另一个类,然后我们只需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) {}
    

    【讨论】:

      【解决方案2】:

      正如我之前的回答中提到的,问题是属性的值是在 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,所以这不是一个普通的属性,也没有在构造函数中设置。相反,我们使用 getter 函数定义属性。这是在 mixin 装饰器中复制的。

      【讨论】:

        猜你喜欢
        • 2011-01-10
        • 1970-01-01
        • 1970-01-01
        • 2022-10-25
        • 2012-02-23
        • 2014-11-29
        • 1970-01-01
        • 2013-10-17
        • 1970-01-01
        相关资源
        最近更新 更多