【问题标题】:Vuex map functions with TypeScript带有 TypeScript 的 Vuex 映射函数
【发布时间】:2021-02-13 21:04:40
【问题描述】:

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

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[]' 类型的参数。”

当将函数的“状态”参数类型定义为“任何”时,它会编译并工作,所以我尝试在 devtools 中“调试”该函数并查看“状态”参数包含什么,它包含我的游戏状态,它具有在 GameState 接口中定义的确切道具。

有谁知道为什么 ts 不允许我用正确的类型定义“状态”参数(这是首先定义接口并避免“任何”的全部目的)

这也不起作用:

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

有没有人遇到过这样的问题?任何想法如何处理它的最佳实践方式?

mapActions 等也一样...

更新 我尝试为我的商店和模块提供更好的类型。现在它们如下: 总店:

export default new Store<RootState>({
  modules: {
    users,
    game,
  },
});

RootState 为:

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 v3.9.7?
  • 不,使用 typecipt 4.0.3。该组件现在基本上什么都没有,只有这个计算的 mapState 函数。商店基本上有一个包含两个命名空间状态的模块对象
  • 显示代码的重点是也许你做了一些你没有意识到的错误。例如“命名空间状态”听起来不正确,它应该是“命名空间模块”。但任何地方都可能存在结构性错误或拼写错误
  • 是的,它们是命名空间模块。我更新了帖子

标签: typescript vue.js vuejs2 vuex typescript4.0


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

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

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

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

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

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

    现在应该输入this.taskTypes

    【讨论】:

    • 谢谢,我想出了类似的东西,但在我看来,为每个从状态映射的 prop im 映射 mapstate 似乎很麻烦,这似乎使代码看起来更复杂,可读性更差.虽然现在这似乎是唯一可行的解​​决方案
    • 是的,这是真的。现在我想到了,您可以尝试创建自己的类型化 mapXX 函数。会让它们很容易阅读。
    【解决方案3】:

    您可以将泛型类型传递给mapState

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

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        猜你喜欢
        • 2017-11-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-29
        • 1970-01-01
        • 2019-06-04
        • 2019-12-27
        • 1970-01-01
        相关资源
        最近更新 更多