Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nuxt with Typescript. It seems `Vue.extend` does not support injected data

I am trying to have typescript support on my Nuxt project.

I understood that I have to use Vue.extend when returning the component data like so:

import Vue from 'vue';

type Data = {
 a: number
}

export default Vue.extend({
 data():Data{
  const a = 3;
  return {
   a
  }
 }
})

However if my component have injected properties, it does not attach those properties to this type.

import Vue from 'vue';

type Data = {
 a: number
}

export default Vue.extend({
 
 inject: ['b'],
 
 data():Data{
  const a = 3;
  const c = this.b
            ^^^^
            // ~~ Property 'b' does not exist on type 'Readonly<Record<never,any>> & Vue' 
  return {
   a
  },
 
  methods:{
   my_method(){
     this.a // no problem here
     this.b // Error here
   }
  }

 }
})

Shouldn't infer also the injected type?

I am forced to use:

const that = this as any;

that I would like to avoid.

like image 542
47ndr Avatar asked Nov 25 '25 07:11

47ndr


1 Answers

You can try to explicitly type this inside data method


import Vue from 'vue';

type Data = {
  a: number
}

export default Vue.extend({

  inject: ['b'],

  data(this: { b: string }): Data {
    const a = 3;
    const c = this.b
    return {
      a
    }
  },

  methods: {
    my_method() {
      this.a // no problem here
      this.b // ok
    }
  }
})

Playground

You can take a look on Vue.extends type definition:

export interface VueConstructor<V extends Vue = Vue> {
  new <Data = object, Methods = object, Computed = object, PropNames extends string = never>(options?: ThisTypedComponentOptionsWithArrayProps<V, Data, Methods, Computed, PropNames>): CombinedVueInstance<V, Data, Methods, Computed, Record<PropNames, any>>;
  // ideally, the return type should just contain Props, not Record<keyof Props, any>. But TS requires to have Base constructors with the same return type.
  new <Data = object, Methods = object, Computed = object, Props = object>(options?: ThisTypedComponentOptionsWithRecordProps<V, Data, Methods, Computed, Props>): CombinedVueInstance<V, Data, Methods, Computed, Record<keyof Props, any>>;
  new (options?: ComponentOptions<V>): CombinedVueInstance<V, object, object, object, Record<keyof object, any>>;


// we are interested in first
  extend<Data, Methods, Computed, PropNames extends string = never>(options?: ThisTypedComponentOptionsWithArrayProps<V, Data, Methods, Computed, PropNames>): ExtendedVue<V, Data, Methods, Computed, Record<PropNames, any>>;




 // ......
  extend<Data, Methods, Computed, Props>(options?: ThisTypedComponentOptionsWithRecordProps<V, Data, Methods, Computed, Props>): ExtendedVue<V, Data, Methods, Computed, Props>;
  extend<PropNames extends string = never>(definition: FunctionalComponentOptions<Record<PropNames, any>, PropNames[]>): ExtendedVue<V, {}, {}, {}, Record<PropNames, any>>;
  extend<Props>(definition: FunctionalComponentOptions<Props, RecordPropsDefinition<Props>>): ExtendedVue<V, {}, {}, {}, Props>;
  extend(options?: ComponentOptions<V>): ExtendedVue<V, {}, {}, {}, {}>;
}

Hence, you can provide explicit generics:

export default Vue.extend<Data, { my_method: () => void }, object, 'b'>({

  inject: ['b'],

  data(): Data {
    const a = 3;
    const c = this.b
    return {
      a
    }
  },

  methods: {
    my_method() {
      this.a // no problem here
      this.b // ok
    }
  }
})
like image 194
captain-yossarian Avatar answered Nov 26 '25 22:11

captain-yossarian



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!