I am trying to create a generic type which will prove typing hints for Vuex mutation. I read this article Vuex + TypeScript and I get inspired to create something more generic. I came up with something like this:
export type MutationType<S, P, K extends keyof P> = Record<K, (state: S, payload: P[K]) => void>;
// S
export type DiceGameState = {
round: number;
score: number;
diceItems: DiceHistoryItem[];
};
// P
export interface DiceGameMutationPayloadMap {
INCREMENT_SCORE: number;
DECREMENT_ROUND: number;
ADD_DICE_HISTORY_ITEM: DiceHistoryItem;
}
// K
export enum DiceGameMutationsKeys {
INCREMENT_SCORE = 'INCREMENT_SCORE',
DECREMENT_ROUND = 'DECREMENT_ROUND',
ADD_DICE_HISTORY_ITEM = 'ADD_DICE_HISTORY_ITEM'
}
export type DiceStoreMutation = MutationType<
DiceGameState,
DiceGameMutationPayloadMap,
keyof typeof DiceGameMutationsKeys
>;
export const mutations: MutationTree<DiceGameState> & DiceStoreMutation = {
DECREMENT_ROUND: (state: DiceGameState, payload: number) => {},
INCREMENT_SCORE: (state: DiceGameState, payload: number) => {},
ADD_DICE_HISTORY_ITEM: (state: DiceGameState, payload: DiceHistoryItem) => {}
};
Where:
S→ type of mutation stateP→ map of mutation name and type of payload assigned to this mutationK→ mutation name
If I check details of this MutationType in my IDE I am getting this hint:
So the key in this object is one of K keys and the value is a method which takes state which is type of S and payload which is type of assigned value to P.
If I try to compile this code I am getting this error:
Error:(7, 3) TS2322: Type '(state: DiceGameState, payload: number) => void' is not assignable to type '(state: DiceGameState, payload: number | DiceHistoryItem) => void'. Types of parameters 'payload' and 'payload' are incompatible. Type 'number | DiceHistoryItem' is not assignable to type 'number'. Type 'DiceHistoryItem' is not assignable to type 'number'.
Do you know how can I make my generic to work ?
Example:
I want to let TS infer the type of payload for a given mutation name. For example if you have a mutation named INCREMENT_SCORE then the type of payload hinted by TS should be a number. This is the reason why I created this: DiceGameMutationPayloadMap, then after creating this const mutations. Typescript should tell me what type payload should have (basing on name of mutation).
A good example of this can be also typing for addEventListenr method provided by TypeScript. This type infers the type of event (ev) basing on a given event name(type):
addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLButtonElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
For more details about this type you should check lib.dom.ts → line 6385

