如何从函数参数数组提取类型并生成泛型交叉类型?
提取数组内对象字段的交叉类型作为函数返回值
要实现create函数返回值为传入数组中所有Extension对象fields的交叉类型,核心在于保留数组元素的具体类型信息,并通过泛型工具类型将这些fields类型交叉合并。
解决步骤及代码实现
1. 定义核心工具类型
先实现一个泛型工具类型,用来递归遍历数组元素,提取每个元素的fields并合并为交叉类型:
type Extension = { name: string, fields: { [key: string]: string } } // 递归拆解数组,将每个元素的fields类型交叉合并 type CombineFields<Ext extends Extension[]> = Ext extends [infer First, ...infer Rest] ? First['fields'] & CombineFields<Rest> : {}
2. 改造create函数的泛型定义
不要使用固定的Config类型(会抹平数组元素的具体类型细节),改用泛型参数让TypeScript自动推导extensions的具体元素类型:
function create<Ext extends Extension[]>(config: { name: string, extensions: Ext }): CombineFields<Ext> { // 合并所有fields的逻辑实现 return config.extensions.reduce((merged, ext) => ({ ...merged, ...ext.fields }), {} as CombineFields<Ext>) }
3. 正确使用示例
注意不要给ext1/ext2手动指定Extension类型,让TypeScript自动推导它们的具体类型,这样才能保留fields的键名信息:
const ext1 = { name: 'ext1', fields: { field1: 'test', field2: 'test' } } const ext2 = { name: 'ext2', fields: { field3: 'test', field4: 'test' } } const config = { name: 'Test', extensions: [ext1, ext2] } // result的类型自动推导为 {field1: string; field2: string} & {field3: string; field4: string} const result = create(config)
可选:保留泛型版Config类型
如果需要保留Config类型的定义,可以将其改为泛型形式:
type Config<Ext extends Extension[]> = { name: string, extensions: Ext } function create<Ext extends Extension[]>(config: Config<Ext>): CombineFields<Ext> { return config.extensions.reduce((merged, ext) => ({ ...merged, ...ext.fields }), {} as CombineFields<Ext>) }
关键原理
- 泛型
Ext extends Extension[]让TypeScript保留数组中每个元素的具体类型,避免用Extension[]统一类型导致的细节丢失。 CombineFields通过条件类型递归拆解数组结构,将每个元素的fields类型依次交叉合并,最终得到所有字段的联合交叉类型。
内容的提问来源于stack exchange,提问作者Jonny Asmar
相关产品推荐
相关产品推荐

