5
votes

Le composant de type Vue JS ne peut pas trouver les propriétés d'instance d'injection

Je travaille avec dactylographié et vue.

Dans mon application, il y a un service qui est un global pour chaque sous-composant.

J'ai trouvé cette solution de vue native sur vue JS pour injecter cette propriété sur les composants enfants.

sur main. ts

import Vue from "vue";

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

sur n'importe quel composant vue typographique

const service = new MyService(...);

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

De cette façon, je peux obtenir le service injecté sur mes composants enfants.

Cependant, j'obtiens l'erreur de mise en jachère

La propriété 'service' n'existe pas sur le type 'CombinedVueInstance >>'.

Comment puis-je résoudre cette erreur de compilation dactylographiée?


0 commentaires

3 Réponses :


0
votes

 Utilisation du décorateur de propriétés Vue

Vue-property-decorator , qui réexporte en interne les décorateurs de vue-class-component , expose une série de décorateurs dactylographiés qui donnent une très bonne intelligence. Vous devez cependant utiliser l'API de classe.

@Inject et @Provide sont deux de ces décorateurs:

Dans le fournisseur :

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

Dans le composant fourni:

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
  },
}

Je pense que c'est la solution optimale, dans le sens où elle donne le meilleure intelligence disponible lorsque vous travaillez avec Vue.

Maintenant, cependant, vous pouvez ne pas vouloir changer la définition de tous vos composants ou tout simplement pas en raison de contraintes externes. Dans ce cas, vous pouvez faire la prochaine astuce:

Diffuser ceci

Vous pouvez lancer ceci à n'importe quel chaque fois que vous êtes sur le point d'utiliser ceci .service . Ce n'est probablement pas la meilleure chose, mais cela fonctionne:

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

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

Il doit y avoir d'autres moyens, mais je ne suis plus habitué à Vue.extends api . Si vous avez le temps et l'opportunité, je vous suggère fortement de passer à l'API de classe et de commencer à utiliser les vues-property-decorators, ils donnent vraiment le meilleur intellisense.


0 commentaires

4
votes

Utilisation de plugins

Si vous souhaitez utiliser un service dans tous les composants Vue, vous pouvez essayer d'utiliser plugins .
Dans main.ts, il vous suffit de l'importer:

import MyService from "@/services/MyService";

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

Dans plugins / myService.ts , vous devez écrire quelque chose comme ceci:

<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>

Et dans n'importe quel composant vue, vous pouvez utiliser ceci:

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 import 'service' from other place
}

_Vue.use(MyServicePlugin);

N'oubliez pas de déclarer $ myService sur Fichier d.ts . Quelque part dans votre projet, ajoutez le fichier myService.d.ts avec le contenu suivant:

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


1 commentaires

Vous devriez probablement aussi ajouter declare module 'vue / types / options' {interface ComponentOptions {myService ?: MyService; }} afin que vous puissiez faire exporter la nouvelle Vue par défaut (myService dans main.ts



3
votes

Vous n'avez pas besoin d'utiliser des composants de classe pour obtenir cela. Pour la déclaration de composant objet, vous avez deux façons de le faire:

Corriger le type de retour de données

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

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

L'inconvénient est que vous devrez le marquer comme facultatif pour pouvoir pour l'ajouter, effectuez un retour de données.

Extension du contexte Vue

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


0 commentaires