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

Posted

技术标签:

【中文标题】Vue JS typescript 组件找不到注入实例属性【英文标题】:Vue JS typescript component cannot find inject instance properties 【发布时间】:2019-08-06 13:40:30 【问题描述】:

我正在使用 typescript 和 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");

在任何 typescript vue 组件上

import Vue from "vue";

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

这样我就可以在我的子组件上获得注入的service

但是我得到了休闲错误

“CombinedVueInstance > > 类型上不存在属性“服务”。

我该如何解决这个打字稿编译错误?

【问题讨论】:

【参考方案1】:

 使用 Vue 属性装饰器

Vue-property-decorator,它在内部从vue-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-decorators,它们确实提供了最好的智能感知。

【讨论】:

是否可以在 Vue 3 + typescript + vue-class-component 的类组件中使用提供/注入,但没有 vue-property-decorator?【参考方案2】:

使用插件

如果你想在所有 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>

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

import MyService from "@/services/MyService";

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

【讨论】:

您可能还应该添加 declare module 'vue/types/options' interface ComponentOptions&lt;V extends Vue&gt; myService?: MyService; 以便您可以在 main.ts 中执行 export default new Vue(myService【参考方案3】:

您不需要使用类组件来获得它。对于对象组件声明,您有两种方法:

修补数据返回类型

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

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

扩展 Vue 上下文

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


export default 
  inject: ['myInjection'],

【讨论】:

【参考方案4】:

仅为注入的组件扩展 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 
  ,
);

【讨论】:

以上是关于Vue JS typescript 组件找不到注入实例属性的主要内容,如果未能解决你的问题,请参考以下文章

Vue + Typescript + Webpack:模块构建失败 - 找不到 vue.esm.js

在 Typescript 文件中导入时找不到 Vue 模块

切换到 Typescript 后找不到 App.js

Storybook 在 React、Next.JS、Typescript 项目中找不到组件

将 vue.js 应用程序中的本地脚本注入不同的组件

Typescript - React 组件中的“找不到名称”错误