我如何正确地键入一个引用其他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.baz
的getters
参数类型为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');