我有一个如下类型:
type EventType = {
event1: undefined,
event2: {
user: number
}
}
type EventName = keyof EventType;
该类型用于输入 logEvent 函数:
function logEvent<T extends EventName>(eventName: T, extraData: EventType[T]) {
}
这确保在调用 logEvent 时,强制执行正确的 eventName 和 extraData 组合:
logEvent('event1', undefined)
logEvent('event2', { user: 5 })
但是,对于第一种情况(未定义),我希望第二个参数是可选的:
logEvent('event1')
logEvent('event2', { user: 5 })
我正在努力寻找解决方案。我的尝试大多都是无用功。
您可能不需要通用函数。相反,您可能需要一个函数,其中参数类型是元组的并集,这些元组表示您允许的所有可能的参数组合。
因此,您需要这样的类型:
现在您可以在
logEvent
函数中使用该类型,如下所示:现在每个事件名称都与特定事件名称所需的其他参数配对。
查看游乐场
那么,如何
EventArgs
从中生成该类型EventType
?使用映射类型来映射每个属性
EventType
并创建每个属性所需的元组。可能看起来像这样:这将映射每个属性,并检查该属性的值是否为
undefined
。 如果是undefined
,则元组只是键名作为函数的一个参数。 如果不是未定义,则使用具有 2 个成员的元组,一个用于键名,一个用于 extraData。查看游乐场
不幸的是,TypeScript 不会自动将接受的尾随参数
undefined
视为可选参数。 microsoft/TypeScript#12400上有此功能请求,但从 TypeScript 5.6 开始它不再是语言的一部分。如果您想要这样的行为,则需要自己编写。假设您想将其保留为通用函数,则有很多方法可以做到这一点。以下是两种:
一种方法是使用条件类型来操作尾随参数的元组类型。以下是其中一种方法:
映射类型 看起来
{[I in keyof T]: undefined}
像T
但每个元素都是undefined
。所以如果T
是[x: string | undefined, y: number]
,那么映射类型看起来像[x: undefined, y: undefined]
。条件类型检查映射类型是否可以分配给T
。如果是,那么整个东西也可能是可选的,如所表示的Partial<T>
。如果不是,那么它就不能是可选的(至少不是整个东西)。所以如果我们对你的函数这样做,我们会得到:当accepts时,其余
[extraData: EventType[K]]
元组将被转换为。让我们测试一下:[extraData?: EventType[K]]
EventType[K]
undefined
或者,如果您不想弄乱其余元组,也可以改用重载。您仍然需要某种条件类型来计算哪些是可选的。对于您的代码,它可能看起来像:
这里返回可分配给相应属性的键
UndefinableKeys<T>
的子集。然后您只需创建两个调用签名,每个调用方式一个:T
undefined
游乐场链接到代码
您可以使用条件休息参数:
操场