正确键入 vuex getter 的 getters 参数



我如何正确地键入一个引用其他getter的vuex getter ?例如:

import { GetterTree } from 'vuex';
class State {
foo: string[] = [];
}
const getters = <GetterTree<State, any>>{
bar: state => state.foo.filter(...something...),
baz: (state, getters) => getters.bar.filter(...something else...)
}

根据vuex的定义,getters.bazgetters参数类型为any。如果可以基于const getters声明将其隐式地类型化为{ bar: string[] },而不必将其声明为接口或类似的类型两次,那就太好了。有办法做到吗?

让我们看看GetterTree的界面:

export interface GetterTree<S, R> {
[key: string]: Getter<S, R>;
}

因此,state => state.foo.filter(...something...)对应Getter<S, R>

不幸的是,第二个参数getters不是通用的,默认类型为any:
export type Getter<S, R> = (state: S, getters: any, rootState: R, rootGetters: any) => any;

来自GetterTree的通用参数R对应于rootState,这对我们来说不感兴趣。

我看到两个选项

第一个-最简单的。

只需在第二个参数中添加显式类型:

const getters: GetterTree<State, any> = {
bar: state => state.foo.filter(e => e.length > 1),
baz: (state, getters: { bar: string[] }) => getters.bar
}

第二种,是覆盖GetterTree内置的实用程序类型。

import { GetterTree, Getter } from 'vuex';
class State {
foo: string[] = [];
}
type CustomGetter<T extends Getter<any, any>, Getters> =
T extends (state: infer State, getters: infer _, rootState: infer RootState, rootGetters: infer RootGetters) => any
? (state: State, getters: Getters, rootState: RootState, rootGetters: RootGetters) => any
: never
type CustomGetterTree<T extends GetterTree<any, any>, Getters> = T extends GetterTree<infer S, infer R> ? {
[key: string]: CustomGetter<Getter<S, R>, Getters>;
} : never
const getters: CustomGetterTree<GetterTree<State, any>, { bar: string[] }> = {
bar: state => state.foo.filter(e => e.length > 1),
baz: (state, getters /** {  bar: string[];} */) => getters.bar
}

游乐场

Edit:如果使用Vue3和TypeScript与Vuex,我会切换到pinia,它似乎有不错的类型安全。至少对我有用。

不知道是否值得考虑另一种方法。我喜欢尝试使用辅助函数推断getter的返回类型。我发现它为我节省了复杂的类型定义,尽管它会导致用于引用getter的键的重复。

const getters = {
gridHeight(): number {
return 32;
},
message(): string {
return 'hello 👋';
},
};
const store = createStore<State>({ getters });
type ReturnOfGetter<T> = T extends (state: infer _, getters: infer _, rootState: infer _, rootGetters: infer _) => infer Return
? Return                                                                                                                          
: never;
export function useGetter<K extends keyof typeof getters>(key: K): ReturnOfGetter<typeof getters[K]> {
return store.getters[key];                                                                                           
};                                                                                                                       

允许这样的访问:

const gridHeight = useGetter<'gridHeight'>('gridHeight');
const message = useGetter<'message'>('message');

最新更新