Vue JS TypeScript component is unable to locate injected instance properties

Currently, I'm utilizing typescript alongside vue in my project.

Within the app structure, there exists a service that acts as a global entity for all sub-components.

I stumbled upon this native solution provided by Vue JS, which facilitates injecting this property into child components.

In the main.ts file:

const service = new MyService(...);

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

For any typescript vue component:

import Vue from "vue";

export default Vue.extend({
  inject: ["service"], // injecting the service
  mounted() {
    console.log(this.service); // access to this.service is available 
  },
});

By following this method, I am successfully able to acquire the injected service within my Child components.

However, an error message is being displayed:

Error - 'Property 'service' does not exist on type 'CombinedVueInstance < Vue, {}, {}, {}, Readonly < Record < never, any > > >'.'

What steps can be taken to rectify this typescript compilation error?

Answer №1

To achieve this, you do not necessarily have to use class components. There are two methods for declaring object components:

Adjusting data return type

export default {
  inject: ['myInjection'],
  data(): { myInjection?: MyInjection } {
    return {}
  },
}

However, the drawback is that you must mark it as optional in order to add it to the data return.

Expanding Vue context

declare module 'vue/types/vue' {
  interface Vue {
    myInjection: MyInjection
  }
}

export default {
  inject: ['myInjection'],
}

Answer №2

Utilizing plugins

If you want to incorporate a specific service across all Vue components, consider leveraging plugins.
Simply import it in your main.ts file:

import Vue from "vue";
import "@/plugins/myService";

In the plugins/myService.ts file, ensure to include something similar to this:

import _Vue from "vue";
import MyService from "@/services/MyService";

export default function MyServicePlugin(Vue: typeof _Vue, options?: any): void {
    Vue.prototype.$myService = new MyService(...); // You can access 'service' from other locations as well
}

_Vue.use(MyServicePlugin);

You can now make use of this service in any Vue component:

<template>
  <div> {{ $myService.name }}</div>
</template>
<script lang="ts">
  import { Component, Vue } from "vue-property-decorator";
  
  @Component
  export default class MyComponent extends Vue {
    private created() {
      const some = this.$myService.getStuff();
    }
  }
</script>

Do not overlook declaring $myService within a d.ts file. Introduce a file named myService.d.ts in your project with the subsequent content:

import MyService from "@/services/MyService";

declare module "vue/types/vue" {
  interface Vue {
      $myService: MyService;
  }
}

Answer №3

Implementing Vue property decorators

Vue-property-decorator, an extension that inherits decorators from vue-class-component, provides a range of TypeScript decorators that enhance intellisense. These decorators are best utilized with the class API.

@Inject and @Provide are among these useful decorators:

In the provider component:

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

@Component
export default class MyClass {
  @Provide('service') service: Service = new MyServiceImpl(); // or any other implementation
}

In the component receiving the provided service:

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

@Component
export default class MyClass {
  @inject('service') service!: Service; // or specific type for this service
  mounted() {
    console.log(this.service); // no TypeScript errors here
  },
}

This approach offers optimal intellisense when working with Vue.

However, in certain scenarios where modifying all components is not feasible, you can use a workaround like:

Typecasting "this"

You have the option to cast this to any before accessing this.service. While not ideal, it gets the job done:

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

There may be alternative methods available, but I am more inclined towards using the class API along with vue-property-decorators for superior intellisense benefits.

Answer №4

Enhance Vue Functionality for Injected Components Only

To optimize Vue performance, create a specialized interface for injection and extend Vue solely for the specific components requiring it:

main.ts:

const customService = new CustomService(...);

export interface ServiceInjector {
  service: CustomService;
}

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

An example component utilizing your interface:

import Vue from "vue";
import { ServiceInjector } from 'main.ts';

export default ( Vue as VueConstructor<Vue & ServiceInjector> ).extend({
  inject: ["service"], // inject the specialized service
  mounted() {
    console.log(this.service); // verify that this.service is available 
  },
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

There is no 'next' property available

export function handleFiles(){ let files = retrieveFiles(); files.next(); } export function* retrieveFiles(){ for(var i=0;i<10;i++){ yield i; } } while experimenting with generators in T ...

Tips for utilizing numerous tables with multiple selection tags

I am struggling with a jQuery issue involving multiple container elements with the class "product-sizes". Each container contains a select option for choosing between inches and centimeters, which triggers the corresponding table display. The problem arise ...

Notification for background processing of $http requests

I am searching for a solution to encapsulate all my AJAX requests using $http with the capability to display a loading gif image during processing. I want this functionality to extend beyond just $http requests, to cover other background processing tasks a ...

Guide to leveraging various build targets while executing the capacitor sync command within an Angular project

In my current Angular project, I have been utilizing Capacitor. Within my angular.json file, I have set up various build targets such as development, staging, and production. To deploy with different configurations, I use the command ng build --configurati ...

Attempting to assign the object retrieved from the interface as the new value for window.location.href

I encountered an issue where the error message Type MyInterface' is not assignable to type 'string' popped up. Although I comprehend the problem, finding a suitable solution has proven to be challenging. MyInterface solely returns one item, ...

Tips for embedding a PHP function within JavaScript code

I am working on enhancing an online application with a translation feature. The application comprises of a frontend coded in HTML and JS, and a backend developed using PHP that is linked to a database. Communication between the frontend and backend occurs ...

What could be the reason that a basic click function fails to locate the selector?

I have created a quick JavaScript module that opens an image and fades out a container to reveal the image. The HTML markup for the image looks like this: <div style="margin-bottom:1px;" class="rsNavItem rsThumb front"> <di ...

How can I substitute a specific capture group instead of the entire match using a regular expression?

I'm struggling with the following code snippet: let x = "the *quick* brown fox"; let y = x.replace(/[^\\](\*)(.*)(\*)/g, "<strong>$2</strong>"); console.log(y); This piece of code replaces *quick* with <strong& ...

Renovating code structure in JavaScript

As I develop a small application that interacts with a database, I have opted to use Promises instead of the callback pattern for simplicity in my code. Through my coding experience, I've noticed a recurring pattern in my logic and I'm seeking ad ...

Is there a way to validate form elements in HTML prior to submitting the form?

In my form, I am utilizing PHP for validation and processing, but I am interested in verifying elements as they are being filled out. Is there a way to check the current value of an element before the form is submitted? ...

What steps should I take to create a React component in Typescript that mimics the functionality of a traditional "if" statement?

I created a basic <If /> function component with React: import React, { ReactElement } from "react"; interface Props { condition: boolean; comment?: any; } export function If(props: React.PropsWithChildren<Props>): ReactElement | nul ...

Ways to resolve the issue of my sidebar displaying at the bottom of the page on smaller screens

Below is the code snippet that generates a Bootstrap page with lorem text and a sidebar. The issue I am facing is that when the browser window size gets smaller, the sidebar appears at the bottom instead of the side. On very small resolutions, it becomes h ...

Issue with React submit button for posting data is not functioning as intended

My dilemma lies within a Modal component containing a Form and Button. The goal is to trigger a POST request (managed in a separate file) upon the user clicking the button, which will run a simulation using the validated input values. Surprisingly, the onC ...

The Nest.js Inject decorator is not compatible with property-based injection

I am facing an issue with injecting a dependency into an exception filter. Here is the dependency in question: @Injectable() export class CustomService { constructor() {} async performAction() { console.log('Custom service action executed ...

Is it feasible to add on to an existing object in the database? (Using Node.js and Mongoose

After saving an object to the database using the following code: var newObject = new PObject({ value : 'before', id : 123456 }); newObject.save(function(err) { if (err) ...

Is there a way to display customized values on a particular column in a Vuetify table?

In the column named conditions, I am looking to display the count of rules > details. Please Note: The array rules has a property details.length = 2 This is what I have attempted https://i.stack.imgur.com/2LoFb.png Here is the code snippet: header ...

Content within a Row of a Data Table

Hello! I am just starting to learn JavaScript and jQuery. Can you help me with an issue I am experiencing? Basically, I have a table and I need to identify which tr contains a td with the text "Weekly", "Daily", or "Monthly". Once I locate that specific t ...

Using jQuery and Bootstrap in an ASP.NET Core project

I am encountering an issue with the configuration of bootstrap and jquery within my project, causing these tools to fail to load properly. The problem seems to be that bootstrap is loading before jquery, resulting in error messages appearing when I check ...

Is there a way to determine the size of an array following the use of innerHTML.split?

There is a string "Testing - My - Example" I need to separate it at the " - " delimiter. This code will help me achieve that: array = innerHTML.split(" - "); What is the best way to determine the size of the resulting array? ...

Unable to successfully upload a .docx file within OnlyOffice utilizing JavaScript

Our application has successfully integrated the OnlyOffice editor. I am currently facing an issue while trying to upload a .docx file from my PC to the OnlyOffice server for later editing. Despite sending a POST request to the server using formdata, the fu ...