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<V extends Vue> 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