Как можно использовать и базовый класс, и миксины с vue-class-component?

Как я могу использовать и базовый класс, и миксин с vue-class-component?

Связывание функций из миксина непосредственно в шаблоне работает нормально, но попытка использовать эти функции в коде машинописного текста вызовет ошибку при компиляции.

Насколько я понимаю, чтобы использовать миксины, вы должны расширять их:

class MyComp extends mixins(MixinA, MixinB)

К сожалению, у меня уже есть базовый класс, так что это не вариант. Вот код, который у меня есть ... есть ли способ сделать это с помощью vue-class-component?

// mixin
@Component
export default class DownloadService extends Vue {
  public downloadModel(id: string) {
    alert('Downloading.');
  }
}

// Base class
@Component({
  props: {
    id: String
  }
})
export default class BaseCard extends Vue {
  id: string;

  protected delete() {
    alert('Deleted');
  }
}


// Child class
@Component({
  props: {
    id: String,
    disabled: Boolean,
  },
  mixins: [DownloadService],
})
export default class ItemCard extends BaseCard {
  protected clicked() {
    // Causes error = S2339: Property 'downloadModel' does not exist on type 'ItemCard'.
    this.downloadModel(this.id);
  }
}

Обратите внимание, что я могу использовать this при необходимости, что будет работать, но это кажется проблематичным, если мне придется делать это повсюду:

  protected clicked() {
    // Ideally shouldn't have to do this casting everywhere. 
    (<DownloadService><any>this).downloadModel(this.id);
  }

person pulekies    schedule 10.08.2018    source источник
comment
Я не пробовал расширять базовый класс, но, пытаясь чисто решить проблему миксинов, я создал следующее: github.com/justrhysism/vue-mixin-decorator - не отправлялся в качестве ответа, и я не уверен, что это действительно так.   -  person justrhysism    schedule 20.08.2018


Ответы (1)


Вы действительно не можете расширить несколько классов. Однако TypeScript также поддерживает миксины.

Сначала вам нужно реализовать класс миксина:

// Child class
@Component({
  props: {
    id: String,
    disabled: Boolean,
  },
  mixins: [DownloadService],
})
export default class ItemCard extends BaseCard implements DownloadService {
  protected clicked() {
    this.downloadModel(this.id);
  }

  // DownloadService declaration
  public downloadModel: (id: string) => void;
}

А затем вызовите функцию, которая применяет миксин к вашему классу:

applyMixins(ItemCard, [DownloadService]);

Функция applyMixins - это функция, которую вы должны включить в свою среду выполнения:

function applyMixins(derivedCtor: any, baseCtors: any[]) {
    baseCtors.forEach(baseCtor => {
        Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
            derivedCtor.prototype[name] = baseCtor.prototype[name];
        });
    });
}

Дополнительную информацию см. В документации TypeScript по миксинам: https://www.typescriptlang.org/docs/handbook/mixins.html


Другой вариант - использовать шаблон класса миксина ECMAScript 2015, который также поддерживается, начиная с TypeScript 2.2.

Сначала вам нужно где-то определить тип для сигнатуры конструкции для определенного типа:

type Constructor<T> = new(...args: any[]) => T;

Затем создайте функцию, которая возвращает новый класс с вашей функциональностью миксина:

function Downloadable<T extends Constructor<{}>>(Base: T) {
  return class extends Base {
    public downloadModel(id: string) {
      alert('Downloading.');
    }
  }
}

Тогда вам все равно понадобится класс с декоратором @Component для определения миксина для Vue:

// mixin
@Component
export class DownloadService extends Downloadable(Vue) {
}

Наконец, вы можете определить класс, в котором вы применяете миксин к базовому классу:

// Child class
@Component({
  props: {
    id: String,
    disabled: Boolean,
  },
  mixins: [DownloadService],
})
export default class ItemCard extends Downloadable(BaseCard) {
  protected clicked() {
    this.downloadModel(this.id);
  }
}
person sroes    schedule 15.08.2018