我的状态(游戏命名空间)有一个接口,如下所示:
interface GameState {
selectedTab: number;
timeout: number;
snackbar: boolean;
text: string;
doneTasks: number;
taskTypes: TaskType[];
stages: Stage[];
}
我正在尝试使用这样的mapState在组件内映射“taskTypes”:
...mapState('game', {
taskTypes: (state: GameState): TaskType[] => state.taskTypes,
}),
我收到以下错误“类型为 '{ taskTypes: (state: GameState) => TaskType[]; }' 的参数不可分配给类型为 'string[]' 的参数。”
将函数的“state”参数类型定义为“any”时,它会编译并工作,所以我尝试在开发工具中“调试”该函数并查看“state”参数保存的内容,它保存我的游戏状态,其中具有 GameState 接口中定义的确切道具。
有谁知道为什么 ts 不允许我用正确的类型定义“状态”参数(这就是首先定义接口并避免“任何”的全部目的)
这也行不通:
...mapState({
taskTypes: ({ state }: Store<GameState>): TaskType[] => state.taskTypes,
}),
有人遇到过这样的问题吗?任何想法如何处理它的最佳实践方法?
mapActions 等也一样...
更新 我尝试为我的商店和模块提供更好的打字效果。现在它们如下: 总店:
export default new Store<RootState>({
modules: {
users,
game,
},
});
根状态为:
export interface RootState {
game: GameState;
users: UserState;
}
游戏模块:
type GameActionContext = ActionContext<GameState, RootState>;
const gameModule: Module<GameState, RootState> = {
namespaced: true,
state: {
selectedTab: 0,
timeout: 5000,
snackbar: false,
text: '',
doneTasks: 0,
taskTypes: [...],
stages: [...],
} as GameState,
mutations: {/*Mutations*/} as MutationTree<GameState>,
actions: {/*Actions*/} as ActionTree<GameState, RootState>,
};
export default gameModule;
我正在尝试通过以下方式映射状态对象:
...mapState({
taskTypes: (state): TaskType[] => state.GameState.taskTypes
})
但我收到错误:
(参数)状态:未知 - 对象的类型为“未知”
发布迄今为止我想出的最佳解决方案(就最少的代码和键入的代码而言):
...mapState({
taskTypes: (state): TaskType[] => (state as RootState).game.taskTypes,
}),
因为 state 将始终等于 RootState,所以每个 mapState 的转换将始终保持相同。不能说我对这个解决方案完全满意,但目前它似乎是最好的一个(不需要任何额外的接口/长线的铸造类型)
我通常必须将对象转换为未知类型,然后转换为实际类型。
您可以尝试这种方法,创建一个像这样的泛型类型,基本上将使值可用作函数:
export type Computed<T> = {
[K in keyof T]: () => T[K];
};
现在您可以在像这样的组件中使用它:
...((mapState('auth', ['taskTypes']) as unknown) as Pick<Computed<GameState>, 'taskTypes'>)
现在应该输入
this.taskTypes
。
您可以将泛型类型传递给
mapState
。
...mapState<GameState>('game', {
taskTypes: (state: GameState): TaskType[] => state.taskTypes,
}),
我在 mapGetters 上收到了相同的错误消息,我在 Vue2 组件中正确键入它的方式如下:
...(mapGetters("module", ['someGetter']) as {someGetter: () => boolean}),
...(mapState("appModule", ["appIsLoading"]) as {appIsLoading: () => boolean;}),
...(mapMutations("appModule", ["SET_APP_IS_LOADING"]) as {SET_APP_IS_LOADING: (payload: boolean) => void;}),
...(mapActions("appModule", ["extendLockTime"]) as {extendLockTime: () => void;}),
使用此类型提示和类型检查在组件内是正确的。
编写了自定义
mapStateRoot
实现(感谢 joakimriedel 的想法)
import { mapState } from 'vuex';
import { ComponentPublicInstance } from 'vue';
type CustomVue = ComponentPublicInstance & Record<string, any>;
type InlineComputed<T extends Function> = T extends (...args: any[]) => infer R ? () => R : never;
/** Based on MapperForState from node_modules/vuex/types/helpers.d.ts */
type ModMapperForState<S> = {
<Map extends Record<string, (this: CustomVue, state: S, getters: any) => any> = {}>(map: Map): {
[K in keyof Map]: InlineComputed<Map[K]>;
};
};
export function constructMapStateRoot<S>() {
return <M extends ModMapperForState<StoreState>>(m: Parameters<M>[0]): ReturnType<M> => {
return mapState(m as any) as ReturnType<M>;
};
}
export mapStateRoot = constructMapStateRoot<StoreState>();
mapStateRoot({
test: s => s.myAwesomeVariable
});