TypeScript如何从交叉类型MainType中移除Node类型
问题原因
两种写法失效的核心原因是对工具类型的适用场景和交叉类型的特性理解有偏差:
Exclude<T, U>仅适用于处理联合类型,作用是从联合类型T中剔除可以赋值给U的成员,逻辑实现为T extends U ? never : T。MainType是交叉得到的单个对象类型,不是联合类型,且这个类型本身可以赋值给Node,因此执行后直接返回never。Omit<T, K>的第二个参数要求传入T的属性名组成的联合类型,作用是删除对象类型T中指定K对应的属性,直接传入Node对象类型不符合参数要求,自然无法正常运行。
另外要注意:TypeScript的交叉类型会在类型检查阶段被扁平化处理,不会记录每个属性来源于哪一个交叉成员,因此不存在可以直接“剥离某一个交叉进来的完整类型”的内置工具。
可行方案
根据开发场景,可以选以下任意一种实现方式:
方案1:直接剔除Node的所有属性
通过keyof Node拿到Node类型的所有公共属性名,用Omit从MainType中删掉这部分属性,剩下的就是自定义结构:
type SecondaryType = Omit<MainType, keyof Node>
这种写法不需要手动列自定义属性名,后续在交叉的自定义部分新增属性时,只要属性名不和Node的属性重名,都会自动被SecondaryType包含。注意:如果自定义属性里存在和Node重名的键,该写法会把重名属性一并剔除,此时优先使用方案3。
方案2:提取明确需要的自定义属性
如果明确知道要保留的自定义属性,直接用Pick提取对应键即可:
type SecondaryType = Pick<MainType, 'id' | 'name' | 'notifications'>
这种写法最直接,计算出的类型和预期结构完全一致。
方案3:提前抽离自定义类型(工程推荐)
把自定义的业务属性单独抽成一个类型,再和Node交叉生成MainType,后续要剥离Node时直接复用抽离的自定义类型即可:
// 单独定义业务侧自定义属性 type CustomProps = { id: string; name: string; notifications: number } // 交叉得到主类型 type MainType = Node & CustomProps // 直接复用自定义类型得到目标结构 type SecondaryType = CustomProps
这种写法维护成本最低,后续修改自定义属性时不需要同步修改Pick/Omit的参数,适合长期维护的项目。
内容的提问来源于stack exchange,提问作者Rishab Gupta
相关产品推荐
相关产品推荐

