如何从函数交叉类型中根据首个参数值提取参数类型?
从函数交叉类型中提取指定首个参数对应的参数类型
我尝试从函数交叉类型中,提取首个参数值为指定内容的对应参数类型,示例代码如下:
type Test = ((evt: 'confirmed', args_0: { overwrite: boolean }) => void) & ((evt: 'canceled') => void); type ExtractArg<T, E> = T extends (evt: E, args: infer P) => void ? P : never; type ExtractConfirmedArgs<T> = T extends (evt: 'confirmed', arg: infer U) => void ? U : never; type EventParameters<T, E> = T extends (evt: infer TE, ...args: infer Args) => void ? (TE extends E ? Args : never) : never; // 无法正常工作 type ConfirmedParameters = EventParameters<Test, 'confirmed'>[0]; // 同样无法正常工作 type P = ExtractArg<Test, 'confirmed'>; type AnotherTry = ExtractConfirmedArgs<Test>;
我期望得到类型ConfirmedArgs = { overwrite: boolean },但上述尝试均失败。想请教是操作有误,还是仅能在联合类型中实现该功能?使用的TypeScript版本为5.4.5。
问题原因
函数交叉类型在条件类型中会被当作整体进行兼容性检查,只有当交叉类型的所有分支都匹配目标函数签名时,条件才会成立。你的Test类型包含两个函数分支,第二个分支(evt: 'canceled') => void不匹配(evt: 'confirmed', arg: infer U) => void签名,因此所有尝试都返回never。
解决方案
通过T extends any ? ...的写法强制触发分布式条件类型,将交叉类型的每个分支单独代入条件判断,相当于把交叉类型“展开”为联合类型处理:
通用提取单个参数类型
type ExtractArg<T, E> = T extends any ? (T extends (evt: E, args: infer P) => void ? P : never) : never; type ConfirmedArgs = ExtractArg<Test, 'confirmed'>; // { overwrite: boolean }
针对特定事件的提取
type ExtractConfirmedArgs<T> = T extends any ? (T extends (evt: 'confirmed', arg: infer U) => void ? U : never) : never; type ConfirmedArgs = ExtractConfirmedArgs<Test>; // { overwrite: boolean }
提取完整参数数组
如果需要提取该事件对应的所有参数组成的数组类型:
type EventParameters<T, E> = T extends any ? (T extends (evt: infer TE, ...args: infer Args) => void ? (TE extends E ? Args : never) : never) : never; type ConfirmedParameters = EventParameters<Test, 'confirmed'>[0]; // { overwrite: boolean }
原理说明
T extends any ? ...会遍历交叉类型的每个分支,对每个分支单独执行后续的条件判断。只有匹配目标签名的分支会返回提取到的类型,不匹配的分支返回never,最终结果为所有有效提取结果的联合(这里仅一个有效结果,即目标类型)。
内容的提问来源于stack exchange,提问作者Maksym
相关产品推荐
相关产品推荐

