kaorun343 / vue-property-decorator

Vue.js and Property Decorator
MIT License
5.52k stars 380 forks source link

@Prop doesn't work on sub class #396

Open movalz opened 3 years ago

movalz commented 3 years ago

Describe the bug When @Prop is defined in a base class and in a sub class of that base class the prop at base class level functions but the sub class prop doesn't function.

To Reproduce

// BaseClass.vue
<script lang="ts">
import { Vue } from 'vue-class-component'
import { Prop } from 'vue-property-decorator'

export default abstract class BaseClass extends Vue {
  @Prop({ required: true }) readonly message: string;

  created() {
    // this works as expected
    console.log("BaseClass - Prop 'message': " + this.message);
  }
}
</script>

// SubClass.vue
<template>
  Property 'message': {{ message }},
  Property 'version': {{ version }}
</template>
<script lang="ts">
import BaseClass from '@/BaseClass.vue';
import { Prop } from 'vue-property-decorator'

export default class SubClass extends BaseClass {
  @Prop({ required: true }) readonly version: number;

  created() {
    // this doesn't work - this.version is undefined
    console.log("SubClass - Prop 'version': " + this.version);
  }
}
</script>

// parent component
...
    <SubClass message="Hello" :version="2.1" />
...

Expected behavior Expected HTML: Property 'message': Hello, Property 'version': 2.1

Created HTML: Property 'message': Hello, Property 'version':

Expected console output: BaseClass - Prop 'message': Hello SubClass - Prop 'version': 2.1

Created console output: BaseClass - Prop 'message': Hello SubClass - Prop 'version': undefined

Screenshots If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

Additional context "vue": "^3.0.4", "vue-class-component": "^8.0.0-rc.1", "vue-property-decorator": "^10.0.0-rc.3",

JohnBernardsson commented 3 years ago

@movalz AFAIK, the vue-property-decorator version with Vue 3 support is 10.0.0, now in rc3: https://github.com/kaorun343/vue-property-decorator/tree/v10.0.0-rc.3

movalz commented 3 years ago

I have checked it with 10.0.0-rc3 - same result.

nros commented 2 years ago

This is not the fault of vue-property-decorator, this is not a bug, its a technical limitation of VueJS!!

@movalz VueJS does not support inheritance at all. AFAIK you can not use a custom base class with your component. This is a limitation based on the technical implementation of Vue 2 and can not be changed. I guess, it is the same with Vue 3.

To overcome this limitiation and provide some simulation of inheritance, Vue uses mix-ins. I guess the Property decorator will work if you mix-in your base class. see: https://vuejs.org/v2/guide/mixins.html

import { Mixins, Prop } from "vue-property-decorator";
import BaseClass from '@/BaseClass.vue';

export default class SubClass extends Mixins(BaseClass) {
    @Prop({ required: true }) readonly version: number;

technical explanation

(see: https://github.com/vuejs/vue/blob/v2.6.14/src/core/global-api/extend.js) Under the hood the @Component decorator calls Vue's API function extend to create the component. This function does not expect to receive a class. It just regards the passed-on class as an object with properties. So, a new default prototype for the component is created and the original base class prototype is just disposed. Therefore, the only base class you can use is Vue. This is the reason, why all component examples extend Vue only and why the SFC TypeScript definition does the same. You can not extend any other base class. You have to use mixins instead. Mixins will copy over all properties and methods of the base class - and only this base class and not of any other super-class - to your component.

(see Line 33)

const Sub = function VueComponent (options) {
    this._init(options)
}
Sub.prototype = Object.create(Super.prototype)
Sub.prototype.constructor = Sub
tokarskadiana commented 2 years ago

@nros Inheritance is working as expected in the Vue 2 component classes, please see the example - test-inheritance-vue2. For Vue 3 it is working with one caveat - you can't extend the class defined in the .vue, only ones defined in .ts (example test-inheritance-vue3).