首页 > 解决方案 > 打字稿:给定一个函数表,创建一个函数,该函数接受表的键和表中函数的第二个参数

问题描述

尝试为状态编写一个简单的存储。

我有一个基本状态:

const state = {
    health: 100,
    maxHealth: 100,
};
type State = typeof state;

我有一组突变

const mutations = {
    setHealth: (state: State, payload: { newHealth: number }) => {
        state.health = payload.newHealth;
    },

    setMaxHealth: (state: State, payload: { newMaxHealth: number }) => {
        state.maxHealth = payload.newMaxHealth;
    },
} as const;
type Mutations = typeof mutations;

我想要做的是创建一个函数,它可以将突变的键作为它的第一个参数,并将突变的有效负载作为它的第二个参数。

我目前有,第一个参数输入正确,但第二个参数mutations[mutation]错误type Parameters<Mutations[M]>[1] is not assignable to parameter of type '{ newHealth: number; } & { newMaxHealth: number; }'.

const commit = <M extends keyof Mutations>(mutation: M, payload: Parameters<Mutations[M]>[1]) => {
    mutations[mutation](state, payload);
};

标签: typescripttypescript-typingstypescript-generics

解决方案


问题是当 TS 想要它时,mutations[mutation]评估(state: State, payload: { newHealth: number } & { newMaxHealth: number }) => void和你的payload变量评估{ newHealth: number; } | { newMaxHealth: number; }{ newHealth: number; } & { newMaxHealth: number; }

这是有道理的,因为 TS 想要mutations[mutation]一次将所有可能的函数视为所有可能的函数。从 TS 的角度来看,为了作为(setHealth | setMaxHealth)payload的参数有效,它必须同时匹配所有可能的函数定义。mutations[mutation]

我处理这个问题的方法是断言mutations[mutation]匹配我们的payload类型:

interface State {
    health: number;
    maxHealth: number;
}

const mutations = {
    setHealth: (state: State, { newHealth }: { newHealth: number }) => {
        state.health = newHealth;
    },

    setMaxHealth: (state: State, { newMaxHealth }: { newMaxHealth: number }) => {
        state.maxHealth = newMaxHealth;
    },
};

type Mutations = typeof mutations;

const o = {
    state: { health: 0, maxHealth: 0 },
    commit<M extends keyof Mutations, P extends Parameters<Mutations[M]>[1]>(mutation: M, payload: P) {
        (mutations[mutation] as (state: State, payload: P) => void)(this.state, payload);
    },
};

o.commit("setHealth", { newHealth: 50 });
o.commit("setMaxHealth", { newMaxHealth: 100 });

(旁注:P对有效负载类型使用泛型意味着具有额外成员的对象将被视为有效,例如o.commit("setMaxHealth", { newMaxHealth: 100, x: 1 })不会出错。如果您不想要此功能,只需在每个地方替换PParameters<Mutations[M]>[1]

祝你好运!


推荐阅读