Vue JS Typescript组件找不到注入实例属性

时间:2019-03-15 13:01:04

标签: javascript typescript vue.js vuejs2

我正在使用打字稿和vue。

在我的应用中,有一个service,它是每个子组件的全局变量。

我在vue JS上发现了this native vue solution,将该属性注入了子组件。

在main.ts上

const service = new MyService(...);

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

在任何打字稿vue组件上

import Vue from "vue";

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

这样,我就可以在自己的Child组件上获得注入的service

但是我遇到了休闲错误

  

类型'CombinedVueInstance >>'上不存在属性'service'。

如何解决此打字稿编译错误?

4 个答案:

答案 0 :(得分:2)

您无需使用类组件即可获取此信息。对于对象组件声明,您有两种方法可以做到:

修补数据返回类型

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

缺点是您必须将其标记为可选,才能添加它以进行数据返回。

扩展Vue上下文

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

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

答案 1 :(得分:1)

使用Vue属性装饰器

Vue-property-decoratorvue-class-component内部重新导出修饰符,它暴露了一系列打字稿修饰符,这些修饰符确实具有很好的智能感。不过,您必须使用类api。

@Inject@Provide是两个这样的修饰符:

在提供者中:

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

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

在提供的组件中:

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

我认为这是最佳的解决方案,从某种意义上说,它提供了使用Vue时更好的智能感知。

但是,现在,您可能不想更改所有组件的定义,或者只是由于外部限制而不能更改。在这种情况下,您可以执行下一个技巧:

对此进行铸造

只要您要使用this,就可以将this.service强制转换为任意值。可能不是最好的东西,但是它可以工作:

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

肯定还有其他方法,但是我已经不习惯使用Vue.extends api了。如果有时间和机会,我强烈建议您切换到类API并开始使用vue-property-decorator,它们确实可以提供最佳的智能感知。

答案 2 :(得分:1)

使用插件

如果您想在所有Vue组件中使用某些服务,则可以尝试使用plugins
在main.ts中,您只需导入它即可:

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

plugins/myService.ts中,您必须这样写:

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

在任何vue组件中,您都可以使用以下代码:

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

请不要忘记在$myService文件中声明d.ts。在项目中的某处添加文件myService.d.ts,其内容如下:

import MyService from "@/services/MyService";

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

答案 3 :(得分:1)

仅为注入的组件扩展 Vue

为注入创建一个接口并在需要的地方为特定组件扩展Vue:

main.ts:

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");

使用你的界面的组件

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 
  },
});
相关问题