如何在TypeScript中实现递归按联合类型省略的类型工具?
实现TypeScript递归类型工具
OmitRecursiveByType<T, P> 下面是满足需求的递归类型工具实现,它会递归处理嵌套对象:移除类型属于指定联合类型P的属性;对于联合类型属性,移除属于P的分支,仅保留剩余类型;若属性处理后变为never则直接移除该属性。
type OmitRecursiveByType<T, P> = // 若当前类型属于P的成员,直接标记为never(后续会被移除) T extends P ? never : // 处理数组类型:递归处理数组元素 T extends Array<infer U> ? Array<OmitRecursiveByType<U, P>> : // 处理对象类型:遍历所有键,仅保留处理后类型不为never的属性 T extends object ? { [K in keyof T as OmitRecursiveByType<T[K], P> extends never ? never : K]: OmitRecursiveByType<T[K], P> } : // 原始类型(非对象、非数组)直接保留 T;
实现逻辑说明
- 联合类型处理:通过
T extends P ? never : ...直接过滤掉属于P的联合分支; - 数组处理:通过类型推断获取数组元素类型
U,递归处理后重新构造数组类型; - 对象处理:遍历对象的每个键,先递归处理属性类型,若处理结果为
never则移除该键,否则保留键并设置处理后的类型; - 原始类型:直接保留,不做处理。
示例场景
示例1:移除嵌套对象中指定类型的属性
type UserProfile = { name: string; age: number; isActive: boolean; meta: { createdAt: string; updatedAt: number; flag: boolean; } }; // 移除所有string类型的属性 type ProfileWithoutStrings = OmitRecursiveByType<UserProfile, string>; // 最终类型: // { // age: number; // isActive: boolean; // meta: { // updatedAt: number; // flag: boolean; // } // }
示例2:处理含联合类型的属性
type Item = { id: string | number; status: 'active' | 'inactive' | boolean; data: { value: number | null | string; tags: Array<string | number | boolean>; } }; // 移除string和boolean类型的分支/属性 type FilteredItem = OmitRecursiveByType<Item, string | boolean>; // 最终类型: // { // id: number; // data: { // value: number | null; // tags: Array<number>; // } // } // 注:status属性处理后变为never,因此被移除
示例3:递归处理嵌套数组和对象
type AppData = { user: { name: string; contacts: Array<{ type: 'email' | 'phone'; value: string; isPrimary: boolean; }>; settings: { darkMode: boolean; language: 'en' | 'fr' | number; } }; timestamp: number; notes: string | null; }; // 移除所有boolean类型的属性 type DataWithoutBooleans = OmitRecursiveByType<AppData, boolean>; // 最终类型: // { // user: { // name: string; // contacts: Array<{ // type: 'email' | 'phone'; // value: string; // }>; // settings: { // language: 'en' | 'fr' | number; // } // }; // timestamp: number; // notes: string | null; // }
示例4:处理对象联合类型
type Entity = { a: string } | { b: number } | { c: boolean }; // 移除所有包含string类型属性的对象分支 type FilteredEntity = OmitRecursiveByType<Entity, string>; // 最终类型:{ b: number } | { c: boolean }
内容的提问来源于stack exchange,提问作者saroro
相关产品推荐
相关产品推荐

