TypeScript中如何递归根据指定对象过滤字段并定义返回类型?
递归剔除对象字段并实现TypeScript类型推导
是否可以根据另一个对象中指定的字段,递归地剔除目标对象中的对应字段?我希望指定API调用需获取的字段,同时让TypeScript正确推导返回值类型(剔除未指定的字段),示例代码如下:
interface Person { head: { hairColor: string eyeColor: string } } const person: Person = { head: { hairColor: 'gray', eyeColor: 'green', } } // 递归将对象所有值转为布尔类型 type BooleanValues<T> = { [K in keyof T]?: T[K] extends object ? BooleanValues<T[K]> : boolean } const fieldsToInclude: BooleanValues<Person> = { head: { hairColor: true, // 无需指定false值,未指定字段默认视为false并被剔除 } } dropFields(person, fieldsToInclude) function dropFields<T>(x: T, y: BooleanValues<T>): IncludeFieldsBasedOn<T, typeof y> { return // ... 待实现逻辑 }
我尝试了如下写法定义IncludeFieldsBasedOn<T, U>,但因类型错误无法运行:
type IncludeFieldsBasedOn<T, O extends BooleanValues<T>> = { [K in keyof T]: T[K] extends object ? IncludeFieldsBasedOn<T[K], O[K]> : O[K] extends true ? T[K] : never }
问题在于该写法无法识别O[K]与T类型的匹配关系。
正确的类型定义与实现
1. 修正IncludeFieldsBasedOn类型
核心思路是提取配置对象中显式设为true的键,再递归处理嵌套对象的字段筛选:
// 递归提取配置对象中值为true的键 type ExtractTrueKeys<U> = { [K in keyof U]: U[K] extends true ? K : U[K] extends object ? ExtractTrueKeys<U[K]> extends infer SubKeys ? SubKeys extends never ? never : K : never : never }[keyof U] // 根据配置生成仅包含指定字段的类型 type IncludeFieldsBasedOn<T, U> = T extends object ? { [K in ExtractTrueKeys<U> & keyof T]: T[K] extends object ? U[K] extends object ? IncludeFieldsBasedOn<T[K], U[K]> : T[K] : T[K] } : T
2. 实现dropFields函数
配合类型定义,编写递归剔除字段的逻辑:
function dropFields<T, U extends BooleanValues<T>>(x: T, y: U): IncludeFieldsBasedOn<T, U> { if (typeof x !== 'object' || x === null) { return x as IncludeFieldsBasedOn<T, U> } const result = {} as IncludeFieldsBasedOn<T, U> for (const key in y) { const configValue = y[key] // 直接保留设为true的字段 if (configValue === true) { (result as any)[key] = x[key as keyof T] } // 递归处理嵌套对象的字段筛选 else if (typeof configValue === 'object' && configValue !== null) { const nestedResult = dropFields(x[key as keyof T], configValue as BooleanValues<T[keyof T]>) // 仅保留有有效字段的嵌套对象 if (Object.keys(nestedResult).length > 0) { (result as any)[key] = nestedResult } } } return result }
类型验证
调用dropFields(person, fieldsToInclude)后,TypeScript会自动推导返回值类型为:
{ head: { hairColor: string } }
内容的提问来源于stack exchange,提问作者Kai Sellgren
相关产品推荐
相关产品推荐

