簡體   English   中英

將具有兩種泛型類型的泛型接口組合為僅具有一種泛型類型的一種類型

[英]Combine generic interfaces with two generic types into one type with only one generic type

就我而言,我正在使用React的useReducer ,但我的問題是純打字稿問題。

采取以下措施:

export interface State<T> {
  values: T;
  someOtherProp: boolean;
}

export interface ActionOne<T, K extends keyof T> {
  type: "UPDATE_VALUE_ONE";
  payload: { name: K; value: T[K] };
}


export interface ActionTwo<T, K extends keyof T> {
  type: "UPDATE_VALUE_TWO";
  payload: { name: K; value: T[K] };
}

現在,將兩個操作接口合並為一個聯合類型:

type ActionTypes<T, K extends keyof T> = ActionOne<T, K> | ActionTwo<T, K>

在下一步中,函數將使用ActionTypes作為其參數的類型:

export const reducer = <T>(
  state: State<T>,
  action: ActionTypes<T> // This already breaks because the second generic type is missing
): State<T> =>
{ 
   switch (action.type) {
     case "UPDATE_VALUE_ONE":
      return {
        ...state,
        values: { ...state.values, [action.payload.name]: action.payload.value}
      };
     case "UPDATE_VALUE_ONE":
    // ...
  }
}

正如您在代碼的注釋中看到的那樣, ActionTypes<T>已經損壞。 就我而言,我不希望reducer函數擔心ActionTypes<T, K>類型K

我知道我可以將keyof T添加到action: ActionTypes<T, keyof T>但是這會破壞此行的類型檢查:

values: { ...state.values, [action.payload.name]: action.payload.value}

因為[action.payload.name]類型可能不同於action.payload.value

實際上,如果ActionType<T, K extends keyof T>僅具有一個通用類型( TActionType<T, K extends keyof T>那將是更加理想的選擇。

如果ActionOneActionTwo是由函數返回的,而不是將它們傳遞為目標,則可以通過內聯聲明這些函數來工作:

type ActionTypes<T> =
 | (<T, K extends keyof T>() => ActionOne<T, K>)
 | (<T, K extends keyof T>() => ActionTwo<T, K>);`

當在僅聲明一個通用類型T另一個接口/類型中使用接口的第二通用類型K的信息時,如何“隱藏”該信息? (特別是如果K仍然是T的依賴項,則K extends keyof T

對於泛型函數,這可以通過內聯聲明解決,那么如何為接口解決呢?

在這種情況下,似乎您希望action參數是所有可能的動作類型的並集...對於keyof T每個可能的K 如果是這樣,我將使用分布式條件類型keyof T的並集keyof T分解為每個單獨的文字K ,並獲取所有ActionTypes<T, K>

type SomeActionOne<T, K extends keyof T = keyof T> = K extends any
  ? ActionOne<T, K>
  : never;
type SomeActionTwo<T, K extends keyof T = keyof T> = K extends any
  ? ActionTwo<T, K>
  : never;
type AllPossibleActionTypes<T> = SomeActionOne<T> | SomeActionTwo<T>;

(更新:我改性的上述版本AllPossibleActionTypes<T>到分布在ActionOne<T, K>對於所有K ,然后分別分配ActionTwo<T, K>對於所有K ,然后統一它們事后注意,這是。當您指定具體類型T ,它的類型完全相同 ,但是當T仍是一個無法解析的泛型時,編譯器會對此做出不同的解釋,特別是在舊版本中,編譯器將等待,直到知道T將類型分為ActionOneActionTwo品種;現在編譯器從一開始就知道這一點。)

那么reducer的簽名將是:

export const reducer = <T>(
  state: State<T>,
  action: AllPossibleActionTypes<T>
): State<T> => { ... }

而且您可以看到在調用reducer()時得到了合理的提示:

reducer(
  { values: { a: "a", b: 1, c: true }, someOtherProp: true },
  { type: "UPDATE_VALUE_TWO", payload: { name: "b", value: 3 } }
); // hinted for value: number when you type in "b" for name

好的,希望能有所幫助; 祝好運!

鏈接到代碼

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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