Skip to content
Advertisement

Vue JS typescript component cannot find inject instance properties

I’m working with typescript and vue.

In my app there is a service which is a global for every sub component.

I found this native vue solution on vue JS to inject this property on the child components.

on main.ts

const service = new MyService(...);

new Vue({
  router,
  provide() { return { service }; } // provide the service to be injected
  render: h => h(App),
}).$mount("#app");

on any typescript vue component

import Vue from "vue";

export default Vue.extend({
  inject: ["service"], // inject the service
  mounted() {
    console.log(this.service); // this.service does exists 
  },
});

This way I’m able to get the injected service on my Child components.

However I’m getting the fallowing error

Property ‘service’ does not exist on type ‘CombinedVueInstance < Vue, {}, {}, {}, Readonly < Record < never, any > > >’.

How can I solve this typescript compilation error?

Advertisement

Answer

 Using Vue property decorator

Vue-property-decorator, which internally re-exports decorators from vue-class-component, expose a series of typescript decorators that give really good intellisense. You must use the class api though.

@Inject and @Provide are two of such decorators:

In the provider:

import {Vue, Component, Provide} from 'vue-property-decorator';

@Component
export default class MyClass {
  @Provide('service') service: Service = new MyServiceImpl(); // or whatever this is
}

In the provided component:

import {Vue, Component, Inject} from 'vue-property-decorator';

@Component
export default class MyClass {
  @inject('service') service!: Service; // or whatever type this service has
  mounted() {
    console.log(this.service); // no typescript error here
  },
}

This I think is the optimal solution, in the sense it gives the better intellisense available when working with Vue.

Now, however, you may don’t want to change the definition of all your components or simply cannot due to external constraints. In such case you can do the next trick:

Casting this

You can cast this to any whenever you’re about to use this.service. Not probably the best thing, but it works:

  mounted() {
    console.log((this as any).service);
  },

There must be other ways, but I’m not used to Vue.extends api anymore. If you have the time and the opportunity, I strongly suggest you to switch to the class API and start using the vue-property-decorators, they really give the best intellisense.

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement