我试图创建将采取单一的实用功能,value
从enum
并将推断基于一个返回的函数的参数interface
有type
相匹配的领域value
。
我正在努力映射value
和查找与字段type
匹配的界面value
enum ActionTypes {
One = 'One',
Two = 'Two',
Three = 'Three'
}
interface Action1 {
type: ActionTypes.One
}
interface Action2 {
type: ActionTypes.Two
meta: {
fieldName: '2'
}
}
interface Action3 {
type: ActionTypes.Three
payload: number[]
meta: {
fieldName: '3'
}
}
type AllActions =
| Action1
| Action2
| Action3
const createAction = <T>(type: T) => (
payload?: //infer payload from AllActions.type === T,
meta?: //infer meta from AllActions.type === T,
) => ({
type,
...payload && { payload },
...meta && { meta }
})
const action1 = createAction(ActionTypes.One)
action1()
const action2 = createAction(ActionTypes.Two)
action2(undefined, {
meta: {
fieldName: '2'
}
})
const action3 = createAction(ActionTypes.Three)
action3([1, 2, 3], {
meta: {
fieldName: '3'
}
})
您可以键入该函数,但是我们需要考虑以下几点:
T
应该扩展AllActions['type']
以便捕获传入的值的文字类型。
要提取与之关联的动作,type: T
我们需要使用预定义的条件类型Extract<AllActions, { type: T }>
将rest参数中的元组与手动声明的元组一起使用将导致参数名称丢失,因此[P, M]
,我们将构建一个函数签名,将参数提取为元组,然后将该元组散布回去,而不是构建像元组并将其散布开来。到rest参数(function fn(...a: Parameters<(x: number) => void>) {}
将有一个名为的数字参数x
,而function fn(...a:[number]) {}
有一个名为的数字参数a_0
,这不理想)
我们可以使用自定义条件类型建立基于存在所需的签名payload
和meta
。
由于包含未解析类型参数的条件类型在编写实现时非常糟糕,因此我们将对内部函数使用单独的实现签名。
将所有这些东西放在一起,我们得到:
type Payload<T> = T extends { payload: infer P } ? P : undefined;
type Metadata<T> = T extends { meta: infer M } ? { meta: M } : undefined;
type CreateActionParameteres<A> = /*4*/ Parameters<
/*5*/ A extends { payload: infer P, meta: infer M } ? /*4*/ (payload: P, meta: { meta: M }) => void :
/*5*/ A extends { payload: infer P } ? /*4*/ (payload: P) => void :
/*5*/ A extends { meta: infer M } ? /*4*/ (payload: undefined, meta: { meta: M }) => void :
() => void>
const createAction = <T extends AllActions['type'] /*1*/ >(type: T) =>
{
function inner(...a: CreateActionParameteres</*2*/ Extract<AllActions, { type: T }>>): /*2*/ Extract<AllActions, { type: T }>
function inner(payload?: Payload<AllActions>, meta?: Metadata<AllActions>) { /*6*/
return {
type,
...payload && { payload },
...meta && { meta }
};
}
return inner;
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句