My current stack includes Typescript, Pinia, and Vue3. I have a MenuButton
component that I want to be able to pass a Pinia store for managing the menu open state and related actions. There are multiple menus in the application, each using the same store factory method to define the stores. I am trying to make this setup work seamlessly with 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>();
Using the store is straightforward:
<template>
<MenuButton
:controller="mainMenu"
></MenuButton>
</template>
<script setup lang=ts">
const mainMenu = useMainMenuStore();
</script>
Initially, there was an error regarding mismatched props. After tweaking the interface as follows, the usage error was fixed, but then another error occurred in the MenuButton
component indicating that toggle()
and isOpen
were unresolved.
export interface MenuStore extends PiniaCustomStateProperties<{
isOpen: RemovableRef<boolean>,
toggle(force?: boolean) : void,
open(): void,
close(): void,
}> {}
Another attempt involved the following tweak:
export interface MenuStore extends Store<string, {
isOpen: RemovableRef<boolean>,
toggle(force?: boolean) : void,
open(): void,
close(): void,
}> {}
This resulted in an error upon usage, though no error in the component itself.
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