vue.js - 在 Vue3 和 TypeScript 中將 Pinia 儲存作為 Prop 傳遞
我正在使用 Typescript、Pinia 和 Vue3,並且有一個 MenuButton 組件,我希望能夠傳入一個 Pinia store,用於控制菜單的開啟狀態,以及顯示/隱藏的操作。應用中有幾個不同的菜單,因此我希望能夠將它們傳入,並且它們都使用相同的工廠來定義 store。我正在嘗試弄清楚如何讓這一切在 Typescript 中運作。
// nav.store.ts
import { defineStore } from "pinia";
import { useStorage } from "@vueuse/core";
import type { RemovableRef } from "@vueuse/core";
export interface MenuStore {
isOpen: RemovableRef<boolean>,
toggle(force?: boolean) : void,
open(): void,
close(): void,
}
interface State {
isOpen: RemovableRef<boolean>;
}
function menuStoreFactory(id: string) {
return defineStore(id, {
state: () : State => ({
isOpen: useStorage(`${id}-open`, false),
}),
actions: {
toggle(force?: boolean) {
this.isOpen = force != undefined ? force : !this.isOpen;
},
open() {
this.isOpen = true;
},
close() {
this.isOpen = false;
}
}
});
}
export const useMainMenuStore = menuStoreFactory('mainMenu');
export const useMobileMenuStore = menuStoreFactory('mobileMenu');
// setup script for the menu button component
import { MenuIcon, MenuLeftIcon } from "@/icons";
import type { MenuStore } from "@/modules/nav/nav.store";
interface Props {
controller: MenuStore
}
const props = defineProps<Props>();
那麼使用方法相當簡單明了:
<template>
<MenuButton
:controller="mainMenu"
></MenuButton>
</template>
<script setup lang=ts">
const mainMenu = useMainMenuStore();
</script>
使用那個當前介面時,我收到了一個錯誤,說 props 不匹配。經過一些研究後,我將介面改為以下這樣,這解決了使用上的錯誤,但隨後在 MenuButton 組件中出現了錯誤,提示 toggle() 和 isOpen 未解析。
export interface MenuStore extends PiniaCustomStateProperties<{
isOpen: RemovableRef<boolean>,
toggle(force?: boolean) : void,
open(): void,
close(): void,
}> {}
另一個接近成功的嘗試性調整是:
export interface MenuStore extends Store<string, {
isOpen: RemovableRef<boolean>,
toggle(force?: boolean) : void,
open(): void,
close(): void,
}> {}
這導致使用時出現此錯誤,但在元件中沒有錯誤
Type _StoreWithState<string, State, {}, {toggle(force?: boolean): void, close(): void, open(): void}> & UnwrapRef<State> & _StoreWithGetters<{}> & {toggle(force?: boolean): void, close(): void, open(): void} & PiniaCustomProperties<string, State, {}, {toggle(force?: boolean): void, close(): void, open(): void}> & PiniaCustomStateProperties<State> is not assignable to type MenuStore ... Type PiniaCustomStateProperties<State> is not assignable to type MenuStore
答案#1
你的問題似乎主要是關於你需要的類型/介面,所以我將回答這個問題。
與其自己寫出一個類型,你可以直接使用返回的 store 的類型。
你有一個工廠函數,它返回 defineStore 的返回值,而 defineStore 本身是一個返回 store 的函數。因此,可以使用 typeof 來獲取工廠函數的類型,然後使用 TypeScript 的 ReturnType 輔助工具來深入獲取返回類型,以找到 store 的類型。
以下應該就是你所需要的全部:
export type MenuStore = ReturnType<ReturnType<typeof menuStoreFactory>>
細目:
ReturnType< // C
ReturnType< // B
typeof menuStoreFactory // A
>
>
- A: 獲取工廠函數的類型。
- B: 獲取工廠函數的返回類型,它是從
defineStore返回的結果。這本身是一個函數,返回 store。 - C: 取得該函數的回傳類型。這就是儲存本身的類型。
