Vue 3 注入打字稿

Vue 3 Inject with Typescript

我使用新的 Vue 3 Composition API 并为响应式数据编写了一个“存储”。

const state = reactive<State>({
  accessToken: undefined,
  user: undefined,
});

export default {
  state: readonly(state),
}

在创建 App 时,我将商店提供给所有组件:

const app = createApp(App)
  .provide("store", store)
  .use(IonicVue)
  .use(router);

最后在组件/视图中,我注入商店以使用它。

export default defineComponent({
  name: "Home",
  inject: ["store"],
  components: {
    IonContent,
    IonHeader,
    IonPage,
    IonTitle,
    IonToolbar,
    IonButton,
  },
  computed: {
    email() {
      return this.store.state.user.email;
    },
  },
});
</script>

不幸的是 Typescript 不喜欢 我在 computed 属性 [=] 中使用 this.store 的方式14=]

并说

Property 'store' does not exist on type 'ComponentPublicInstance<{}, {}, {}, { email(): any; }, {}, EmitsOptions, {}, {}, false, ComponentOptionsBase<{}, {}, {}, { email(): any; }, {}, ComponentOptionsMixin, ComponentOptionsMixin, EmitsOptions, string, {}>>'

我的意思是当我删除 <script/> 标签中的 lang="ts" 时一切正常,但没有显示错误。 关于如何解决这个问题或它的具体含义有什么建议吗?

提前致谢!

我建议将商店用作全局 属性 而无需在任何子组件中指定 inject 因为 provide/inject 可能有一些 reactivity 警告:

const app = createApp(App)
  .use(IonicVue)
  .use(router);
app.config.globalProperties.store= store;

declare module '@vue/runtime-core' {
  interface ComponentCustomProperties  {
       store:any // replace it with the right type
     }
   }

那就直接用吧:

export default defineComponent({
  name: "Home",
  components: {
  ...
  },
  computed: {
    email() {
      return this.store.state.user.email;
    },
  },
});
</script>

对于那些使用 Vue 3 + TS 处理相同问题的人,我找到了一个解决方案,无需更改 app.config 或声明新的 module:

  1. App.ts 设置
import { createApp, reactive } from 'vue'
import App from './App.vue'

const Store = reactive({
  myProperty: 'my value'
})

createApp(App)
  .provide('Store', Store)
  .mount('#app')
  1. 访问注入反应对象的组件:
<template>
  <div>{{ Store.myProperty }}</div>
</template>

<script lang="ts">
import { IStore } from '@/types'
import { defineComponent, inject } from 'vue'

export default defineComponent({
  name: 'MyComponentName',
  setup() {
    return {
      Store: inject('Store') as IStore,
    }
  },
  created() {
    console.log(this.Store) // will show the `Store` in the console
  }
})
</script>
  1. Store (@/types.ts) 的类型定义:
export interface IStore {
  myProperty: string
}

按照这 3 个步骤,我可以使用 TypeScript read/write 到 Store.myProperty 而没有问题