将具有两种泛型类型的泛型接口组合为仅具有一种泛型类型的一种类型

时间:2019-07-28 16:39:21

标签: reactjs typescript generics typescript-generics

就我而言,我正在使用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函数担心K的{​​{1}}是什么类型。

我知道我可以将ActionTypes<T, 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>),则更为理想。

如果TActionOne是由函数返回的,而不是像目标那样直接传递它们,它将通过内联声明这些函数来工作:

ActionTwo

问题

当在仅声明一个通用类型type ActionTypes<T> = | (<T, K extends keyof T>() => ActionOne<T, K>) | (<T, K extends keyof T>() => ActionTwo<T, K>);` 的另一个接口/类型中使用接口的第二通用类型K的信息时,如何“隐藏”该信息? (特别是如果T始终由K依赖于T。)

对于泛型函数,这可以通过内联声明解决,那么如何为接口解决呢?

1 个答案:

答案 0 :(得分:0)

在这种情况下,似乎您希望action参数是所有可能的操作类型的并集...对于K中的每个可能的keyof T。如果是这样,我将使用distributive conditional type将联合keyof T分解为每个单独的文字K,并获得所有ActionTypes<T, K>的联合:

type AllPossibleActionTypes<T, K extends keyof T = keyof T> = K extends any
  ? ActionTypes<T, K>
  : never;

然后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

好的,希望能有所帮助;祝你好运!

Link to code