簡體   English   中英

輸入 vuex store 的通用類型

[英]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 → 突變類型 state
  • P → 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM