如何用TypeScript为Store选择器函数的返回值标注类型?
问题分析与解决方案
问题根源
- Listener类型约束过紧:原定义的
Listener<TStore>强制selectorFn返回完整的TStore类型,但实际选择器需要返回Store的部分数据(比如单个字段的number类型),导致类型不匹配。 - useStore泛型无关联约束:直接给
useStore添加泛型T时,TypeScript无法确认T与TStore的派生关系,因此抛出"任意类型可能与TStore无关"的错误。
修正方案
1. 调整Listener类型,支持任意返回值
将selectorFn的返回类型改为unknown,兼容所有可能的选择器返回结果:
type Listener<TStore> = { selectorFn: (store: TStore) => unknown }
2. 正确标注useStore的泛型
给useStore的泛型T设置默认值为TStore(对应不传选择器时返回整个Store的场景),同时明确选择器函数的类型为(store: TStore) => T:
function useStore<T = TStore>(selectorFn: (store: TStore) => T = (store) => store as T): T { const listener = { selectorFn, // 其他内容 } listeners.add(listener) return selectorFn(store) }
这里的as T是安全断言:默认选择器返回完整的TStore,而泛型T的默认值就是TStore,类型完全匹配。
完整修正代码
type Listener<TStore> = { selectorFn: (store: TStore) => unknown } function createStore<TStore>(store: TStore) { const listeners = new Set<Listener<TStore>>() function useStore<T = TStore>(selectorFn: (store: TStore) => T = (store) => store as T): T { const listener = { selectorFn, // 其他内容 } listeners.add(listener) return selectorFn(store) } return [useStore] } const [useStore] = createStore({ count: 0, input: '' }) function DisplayStore() { const count = useStore((store) => store.count) // 类型正确,count为number const fullStore = useStore() // 类型正确,为{count: number; input: string} }
补充说明
如果后续需要在触发监听时处理选择器的返回值,可以通过类型守卫将unknown类型转换为具体类型;泛型T = TStore确保了不传选择器时,默认返回完整Store的类型,符合预期行为。
内容的提问来源于stack exchange,提问作者user3331344
相关产品推荐
相关产品推荐

