如何基于Type<Param>创建类型,实现对象类型合并?
问题描述
我定义了以下类型与变量:
type ToConcat<M> = {} const mid1:ToConcat<{foo:'bar'}> = {} const mid2:ToConcat<{john:'doe'}> = {}
我想要实现:
const finalObject = [mid1, mid2, myAttempted]
其中myAttempted的类型是mid1和mid2对应类型的合并结果,也就是:
{ foo: 'bar', john:'doe' }
我尝试了下面的代码但无法正常运行:
type Mid<L> = { locals: L } type Fi<M extends Mid<any>[]> = { [key in keyof M[number]['locals']]: M[number]['locals'][key] } const mi1:Mid<{foo:'bar'}> = { locals: {foo: "bar"} } const mi2:Mid<{john:'doe'}> = { locals: {john: "doe"} } type P<R extends Mid<any>[]> = [...R, Fi<R>] const g:P<[typeof mi1, typeof mi2]> = [mi1, mi2, { locals: { // 此处无法得到类型提示与校验 } }]
我的最终需求是:仅需声明mid1、mid2为对象,即可得到对应的合并类型。
解决方案
核心问题分析
你之前的Fi类型使用M[number]['locals']会得到联合类型的键,但值会变成所有对应类型的联合,并且无法正确合并成交叉类型,导致类型提示失效。我们需要先从ToConcat<M>中提取内部类型,再将这些类型合并为交叉类型,最终生成目标对象类型。
实现代码
// 从ToConcat<M>中提取内部泛型类型 type ExtractToConcatType<T> = T extends ToConcat<infer U> ? U : never; // 将联合类型转换为交叉类型的工具类型 type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; // 合并数组中所有ToConcat对应的内部类型 type MergeToConcat<T extends ToConcat<any>[]> = UnionToIntersection<ExtractToConcatType<T[number]>>; // 定义最终数组的类型结构:原对象 + 合并后的对象 type FinalArray<T extends ToConcat<any>[]> = [...T, MergeToConcat<T>]; // 你的原始类型与变量定义 type ToConcat<M> = {} const mid1: ToConcat<{ foo: 'bar' }> = {} const mid2: ToConcat<{ john: 'doe' }> = {} // 使用示例:手动指定类型 const finalObject: FinalArray<[typeof mid1, typeof mid2]> = [mid1, mid2, { foo: 'bar', john: 'doe' }]
简化使用:自动推导类型
如果不想手动指定泛型参数,可以写一个辅助函数自动推导:
function createFinalArray<T extends ToConcat<any>[]>(...args: [...T, MergeToConcat<T>]) { return args; } // 直接传入参数即可,自动推导合并类型 const finalObject = createFinalArray(mid1, mid2, { foo: 'bar', john: 'doe' });
代码说明
- ExtractToConcatType:通过条件类型的
infer关键字,精准提取ToConcat包裹的内部类型。 - UnionToIntersection:TypeScript经典工具类型,将联合类型转为交叉类型,实现多个对象类型的合并。
- MergeToConcat:基于前两个工具类型,得到所有
ToConcat对象对应的内部类型的合并结果。 - FinalArray:构造数组类型,确保前两个元素是原
ToConcat对象,最后一个元素是合并后的类型,提供完整的类型提示与校验。
内容的提问来源于stack exchange,提问作者BENARD Patrick
相关产品推荐
相关产品推荐

