Миксины Typescript со значениями свойств по умолчанию (производными от нового MyClass) - PullRequest
0 голосов
/ 09 февраля 2019

Я экспериментирую с некоторыми миксинами в 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.

Я рассмотрел вопрос об установке этого параметра в конструкторе, но я не уверен, как работают конструкторы в миксинах ...

Я предполагаю, что это должно быть возможно.

Используемый мной в настоящее время миксин-метод представляет собой миксин-декоратор:

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 голосов
/ 11 февраля 2019

Как упоминалось в моем предыдущем ответе, проблема заключается в том, что значение свойства задается в конструкторе класса mixin, а конструктор игнорируется в декораторе mixin.

Другой способ - неустановите значение свойства в конструкторе, но вместо этого определите свойство с помощью метода получения и установки:

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();
    }
}

На самом деле в этом случае установщик не требуется, поскольку значение только для чтения полезно.Так как мы используем геттер, это не обычное свойство и не устанавливается в конструкторе.Скорее мы определяем свойство с помощью функции получения.Это копируется в миксин-декоратор.

0 голосов
/ 11 февраля 2019

Основная причина этой проблемы заключается в том, что при определении значения свойства для класса, когда оно переносится в JavaScript , это значение устанавливается в конструкторе .Приведенный выше смешанный код специально игнорирует конструктор.Реальным решением здесь является объединение двух конструкторов классов.

В Typescript есть два разных подхода к миксинам.Подходы похожи на те, что в моем вопросе, когда мы перебираем свойства прототипа и копируем их из одного класса в другой, а другой, где мы просто возвращаем новый класс, расширяющий исходный :

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

Я думал, что не смогу использовать это в angular, поскольку это функция, которая возвращает новый класс, но это вполне возможно, как показано здесь :

class SourceClass{}

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