Search code examples
vue.jsvuejs3vue-composition-apivue-class-components

Is it possible to use Vue 3 with the composition API and vue class components?


We've built a project for the last 8 months using vue 3 and and the class components, but as it seems like it's no longer maintained, we'd like to gradually switch to the composition API, and more precisely to the setup script syntax.

We are currently using vue3.0.0 and vue-class-components 8.0.0.

Our goal would be, as we have to keep adding new features to the project, to start creating the new components with the composition API, while keeping those already written with vue class component. And, as we go along, we'll try to rewrite them with the composition API.

I tried to create a simple HelloWorld component using vue class components :

<template>
 <div>
   <TestComponent :test="'test string'" />
 </div>
</template>

<script lang="ts">
import { Options, Vue } from 'vue-class-component';
import TestComponent from './TestComponent.vue';

@Options({
 components: { TestComponent }
})
export default class HelloWorld extends Vue {
}
</script>

and add a test component :

<template>
  <h1>Test composant {{ test }}</h1>
</template>

<script lang="ts">
export default {
  name: 'TestComponent',
  props: { test: {type: String, required: true }},
  setup(props: { test: string }, context: unknown) { console.log(context); return { test: props.test } }
}
</script>

However, I come up with an error in my code : when declaring the TestComponent in the HelloWorld, the compiler tells me that he's expecting the argument 'test' as declared in the TestComponent :

Argument of type '{ name: string; props: { test: StringConstructor; required: boolean; }; setup(props: { test: string; }, context: unknown): { test: string; }; }' is not assignable to parameter of type 'Component<any, any, any, ComputedOptions, MethodOptions>'.
  Type '{ name: string; props: { test: StringConstructor; required: boolean; }; setup(props: { test: string; }, context: unknown): { test: string; }; }' is not assignable to type 'ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any>'.
    Type '{ name: string; props: { test: StringConstructor; required: boolean; }; setup(props: { test: string; }, context: unknown): { test: string; }; }' is not assignable to type 'ComponentOptionsBase<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}>'.
      Types of property 'setup' are incompatible.
        Type '(props: { test: string; }, context: unknown) => { test: string; }' is not assignable to type '(this: void, props: Readonly<LooseRequired<any>>, ctx: SetupContext<any>) => any'.
          Types of parameters 'props' and 'props' are incompatible.
            Property 'test' is missing in type 'Readonly<LooseRequired<any>>' but required in type '{ test: string; }'.ts(2345)
TestComponent.vue.ts(5, 18): 'test' is declared here.

UPDATE : I tried to register the TestComponent globally in the main.ts, but the error is still the same

Is there a way to make the two work together?


Solution

  • One issue is your props declaration is incorrect. It should be:

    // ❌ invalid
    // props: {
    //   test: String,
    //   required: true
    // },
    
    props: {
      test: {
        type: String,
        required: true
      }
    },
    

    Also you don't need to type the arguments of setup(), as they are normally inferred from the defineComponent() utility, which enables type inference in Vue components:

    // export default {
    //   setup(props: { test: string }, context: unknown) { /*...*/ }
    // }
    
    import { defineComponent } from 'vue'
    export default defineComponent({
      setup(props, context) { /*...*/ }
    })