[英]Generic type for typing vuex store
我正在嘗試創建一個通用類型,它將證明Vuex
突變的鍵入提示。 我讀了這篇文章Vuex + TypeScript ,我受到啟發去創造一些更通用的東西。 我想出了這樣的事情:
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) => {}
};
在哪里:
S
→ 突變類型 stateP
→ map 的突變名稱和分配給該突變的有效負載類型K
→ 突變名稱如果我在我的 IDE 中檢查此MutationType
的詳細信息,我會得到以下提示:
所以這個 object 中的鍵是K
鍵之一,值是一個方法,它采用 state ,它是S
的類型,有效負載是分配給P
的值的類型。
如果我嘗試編譯此代碼,則會出現此錯誤:
錯誤:(7, 3) TS2322:類型“(state: DiceGameState, payload: number) => void”不可分配給類型“(state: DiceGameState, payload: number | DiceHistoryItem) => void”。 參數類型“payload”和“payload”不兼容。 輸入'數字| DiceHistoryItem' 不可分配給類型 'number'。 類型“DiceHistoryItem”不可分配給類型“number”。
你知道我怎樣才能讓我的通用工作嗎?
我想讓 TS 推斷給定突變名稱的有效負載類型。 例如,如果您有一個名為INCREMENT_SCORE
的突變,則 TS提示的payload
類型應該是一個數字。 這就是我創建這個的原因: DiceGameMutationPayloadMap
,然后在創建這個const mutations
之后。 Typescript 應該告訴我有效載荷應該有什么類型(基於突變的名稱)。
一個很好的例子就是為 TypeScript 提供的addEventListenr
方法鍵入。此類型根據給定的事件名稱( type
) 推斷事件的類型 ( ev
):
addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLButtonElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
有關此類型的更多詳細信息,您應該查看lib.dom.ts → 第 6385 行
實際上,這是可能的。 我花了一些時間才弄清楚我做錯了什么,但最后我明白了我的錯誤。
我的第一個錯誤是在DiceStoreMutation
內部,因為我這個泛型的第三個參數指的是沒有鍵名的鍵類型。 我們可以在附加的屏幕截圖中看到這一點的證明:
我們可以看到Expanded顯示p
實際上是一個字符串,但它應該是字符串'ADD_DICE_HISTORY_ITEM' | 'DECREMENT_ROUND' | 'INCREMENT_SCORE'
的並集'ADD_DICE_HISTORY_ITEM' | 'DECREMENT_ROUND' | 'INCREMENT_SCORE'
'ADD_DICE_HISTORY_ITEM' | 'DECREMENT_ROUND' | 'INCREMENT_SCORE'
。 你可能認為也許我應該使用keyof DiceGameMutationsKeys
而不是keyof typeof DiceGameMutationsKeys
,后者將引用此接口的鍵名稱而不是鍵類型,但這當然會按預期發生錯誤。 這讓我覺得我應該以某種方式更改我的通用MutationType
。 在我閱讀了@Joel Bourbonnais 的回答並檢查了這個關於P[K]
部分是Index types
的很好的例子之后。 我為我的MutationType
想出了一個新想法: Mapped generics
+ Index types
。 這個新類型想出了這個形狀:
export type MutationType<T, U> = {
[K in keyof U]: (state: T, payload: U[K]) => void;
};
我只能說一件事它很有效。 現在我什至不需要DiceGameMutationsKeys
,因為DiceGameMutationPayloadMap
提供了所有信息。 你可能會問為什么? 我已經急着解釋了:
K in keyof U
所以K
只能是U
的一個鍵,所以它將是U
鍵接口的字符串文字的並集。U[K]
所以它將查找K
鍵下的U
類型( U
鍵接口的字符串文字聯合之一)您可以在下面找到帶有證據的屏幕截圖:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.