Vue中如何定义带类型约束的Pinia泛型Store工厂?
问题分析与解决思路
核心问题原因
你的代码有两个关键错误:
useFooStore的定义方式错误:defineStore本身返回的是一个可直接调用的Store钩子函数,但你把useFooStore包裹成了一个返回该钩子的函数。导致调用useFooStore()时,得到的是钩子函数而非Store实例,自然找不到collection属性。collection初始化错误:用{} as Map<string, T>把空对象断言为Map,运行时会因为空对象没有Map的方法(如set/get)导致报错。
分步解决方案
1. 修正Store钩子的定义
把useFooStore直接赋值为工厂函数的返回结果,不需要额外函数包裹:
// 错误写法 export const useFooStore = () => kindStoreFactory<Foo>('foo') // 正确写法 export const useFooStore = kindStoreFactory<Foo>('foo')
之后在组件中调用const fooStore = useFooStore(),就能拿到带有collection属性的Store实例。
2. 修复collection的初始化逻辑
直接创建Map实例,避免类型断言带来的运行时问题:
export const kindStoreFactory = <T extends { id: string }>( name: string ) => { return defineStore(name, () => { // 替换空对象断言为Map实例 const collection = ref(new Map<string, T>()) return { collection } }) }
3. 可选:添加通用操作方法(增强实用性)
可以在工厂函数中封装通用的CRUD方法,避免重复代码:
import { defineStore } from 'pinia' export const kindStoreFactory = <T extends { id: string }>( name: string ) => { return defineStore(name, () => { const collection = ref(new Map<string, T>()) // 添加资源 const add = (item: T) => { collection.value.set(item.id, item) } // 获取资源 const get = (id: string) => { return collection.value.get(id) } // 删除资源 const remove = (id: string) => { collection.value.delete(id) } return { collection, add, get, remove } }) }
验证修正后的使用示例
在组件中调用:
<script setup lang="ts"> import { useFooStore } from '@/stores/foo' const fooStore = useFooStore() // 正常访问collection console.log(fooStore.collection) // 添加Foo实例 fooStore.add({ id: 'foo_001', /* Foo的其他属性 */ }) // 获取指定ID的Foo const targetFoo = fooStore.get('foo_001') </script>
内容的提问来源于stack exchange,提问作者Eamon Bauman
相关产品推荐
相关产品推荐

