Je travaille avec tapuscrit et vue.

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

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

Sur main.ts

const service = new MyService(...);

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

Sur n'importe quel composant vue dactylographié

import Vue from "vue";

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

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

Cependant, je reçois l'erreur suivante

La propriété 'service' n'existe pas sur le type 'CombinedVueInstance < Vue, {}, {}, {}, Readonly < Record < never, any > > >'.

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

5
Daniel Santos 15 mars 2019 à 16:01

4 réponses

Meilleure réponse

Utiliser le 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 tapuscrits qui donnent un très bon intellisense. Vous devez cependant utiliser l'API de classe.

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

Chez le fournisseur :

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

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

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 meilleur intellisense disponible lorsque vous travaillez avec Vue.

Maintenant, cependant, vous ne voudrez peut-être pas changer la définition de tous vos composants ou ne pouvez tout simplement pas en raison de contraintes externes. Dans ce cas, vous pouvez faire l'astuce suivante :

Jeter ça

Vous pouvez lancer this sur n'importe quel moment lorsque vous êtes sur le point d'utiliser this.service. Pas probablement la meilleure chose, mais ça marche :

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

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 vue-property-decorators, ils donnent vraiment le meilleur intellisense.

0
Community 20 juin 2020 à 09:12

Utiliser des plugins

Si vous souhaitez utiliser un service dans tous les composants Vue, vous pouvez essayer d'utiliser des plugins .
Dans main.ts, importez-le simplement :

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

Dans plugins/myService.ts, vous devez écrire quelque chose comme 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);

Et dans n'importe quel composant vue, vous pouvez utiliser 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>

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

import MyService from "@/services/MyService";

declare module "vue/types/vue" {
  interface Vue {
      $myService: MyService;
  }
}
4
Alex 15 mars 2019 à 13:56

Étendre Vue pour les composants injectés uniquement

Créez une interface pour l'injection et étendez Vue pour les composants spécifiques là où cela est nécessaire :

Maintes:

const service = new MyService(...);

export interface ServiceInjection {
  service: MyService;
}

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

Un composant qui utilise votre interface

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

export default ( Vue as VueConstructor<Vue & ServiceInjection> ).extend({
  inject: ["service"], // inject the service
  mounted() {
    console.log(this.service); // this.service does exists 
  },
});
1
Michael Große 20 janv. 2021 à 15:33

Vous n'avez pas besoin d'utiliser des composants de classe pour obtenir cela. Pour la déclaration de composant objet, vous avez deux manières de procéder :

Type de retour de données de correctif

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

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

Extension du contexte Vue

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

export default {
  inject: ['myInjection'],
}
3
CyberAP 26 juil. 2020 à 18:33