[英]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>
仅具有一个通用类型( T
) ActionType<T, K extends keyof T>
那将是更加理想的选择。
如果ActionOne
和ActionTwo
是由函数返回的,而不是将它们传递为目标,则可以通过内联声明这些函数来工作:
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
将类型分为ActionOne
和ActionTwo
品种;现在编译器从一开始就知道这一点。)
那么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.