Vuex 与 TypeScript 映射函数

问题描述 投票:0回答:5

我的状态(游戏命名空间)有一个接口,如下所示:

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
})

但我收到错误:

(参数)状态:未知 - 对象的类型为“未知”

typescript vue.js vuejs2 vuex typescript4.0
5个回答
3
投票

发布迄今为止我想出的最佳解决方案(就最少的代码和键入的代码而言):

...mapState({
  taskTypes: (state): TaskType[] => (state as RootState).game.taskTypes,
}),

因为 state 将始终等于 RootState,所以每个 mapState 的转换将始终保持相同。不能说我对这个解决方案完全满意,但目前它似乎是最好的一个(不需要任何额外的接口/长线的铸造类型)


1
投票

我通常必须将对象转换为未知类型,然后转换为实际类型。

您可以尝试这种方法,创建一个像这样的泛型类型,基本上将使值可用作函数:

export type Computed<T> = {
    [K in keyof T]: () => T[K];
};

现在您可以在像这样的组件中使用它:

...((mapState('auth', ['taskTypes']) as unknown) as Pick<Computed<GameState>, 'taskTypes'>)

现在应该输入

this.taskTypes


0
投票

您可以将泛型类型传递给

mapState

...mapState<GameState>('game', {
  taskTypes: (state: GameState): TaskType[] => state.taskTypes,
}),

0
投票

我在 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;}),

使用此类型提示和类型检查在组件内是正确的。


0
投票

编写了自定义

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
});
© www.soinside.com 2019 - 2024. All rights reserved.